Full Code of tighten/lambo for AI

main 2fea00e4e457 cached
107 files
226.1 KB
54.9k tokens
434 symbols
1 requests
Download .txt
Showing preview only (251K chars total). Download the full file or copy to clipboard to get everything.
Repository: tighten/lambo
Branch: main
Commit: 2fea00e4e457
Files: 107
Total size: 226.1 KB

Directory structure:
gitextract_7pldj4rw/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       └── run-tests.yml
├── .gitignore
├── .phpcs.xml.dist
├── LICENSE.TXT
├── app/
│   ├── Actions/
│   │   ├── AbortsCommands.php
│   │   ├── Concerns/
│   │   │   ├── InteractsWithComposer.php
│   │   │   ├── InteractsWithGitHub.php
│   │   │   └── InteractsWithNpm.php
│   │   ├── CreateDatabase.php
│   │   ├── CustomizeDotEnv.php
│   │   ├── DisplayHelpScreen.php
│   │   ├── DisplayLamboWelcome.php
│   │   ├── EditConfigFile.php
│   │   ├── GenerateAppKey.php
│   │   ├── InitializeGitHubRepository.php
│   │   ├── InitializeGitRepository.php
│   │   ├── InstallBreeze.php
│   │   ├── InstallJetstream.php
│   │   ├── InstallLaravel.php
│   │   ├── InstallNpmDependencies.php
│   │   ├── MigrateDatabase.php
│   │   ├── OpenInBrowser.php
│   │   ├── OpenInEditor.php
│   │   ├── PushToGitHub.php
│   │   ├── RunAfterScript.php
│   │   ├── UpgradeSavedConfiguration.php
│   │   ├── ValetLink.php
│   │   ├── ValetSecure.php
│   │   ├── ValidateGitHubConfiguration.php
│   │   ├── VerifyDependencies.php
│   │   └── VerifyPathAvailable.php
│   ├── Commands/
│   │   ├── .gitkeep
│   │   ├── Debug.php
│   │   ├── EditAfter.php
│   │   ├── EditConfig.php
│   │   ├── HelpCommand.php
│   │   ├── LamboCommand.php
│   │   └── NewCommand.php
│   ├── Configuration/
│   │   ├── CommandLineConfiguration.php
│   │   ├── LamboConfiguration.php
│   │   ├── SavedConfiguration.php
│   │   ├── SetConfig.php
│   │   └── ShellConfiguration.php
│   ├── ConsoleWriter.php
│   ├── Environment.php
│   ├── Helpers/
│   │   └── GetTimezone.php
│   ├── LamboException.php
│   ├── LogsToConsole.php
│   ├── Options.php
│   ├── Providers/
│   │   └── AppServiceProvider.php
│   ├── Shell.php
│   └── Tools/
│       └── Database.php
├── bin/
│   └── testLambo.sh
├── bootstrap/
│   └── app.php
├── box.json
├── builds/
│   └── lambo
├── composer.json
├── config/
│   ├── app.php
│   └── commands.php
├── lambo
├── phpunit.xml.dist
├── readme.md
├── stubs/
│   ├── after
│   └── config
├── tests/
│   ├── CreatesApplication.php
│   ├── Feature/
│   │   ├── CreateDatabaseTest.php
│   │   ├── CustomizeDotEnvTest.php
│   │   ├── EditConfigFileTest.php
│   │   ├── Fakes/
│   │   │   └── FakeProcess.php
│   │   ├── Fixtures/
│   │   │   ├── .lambo/
│   │   │   │   ├── commented_configuration
│   │   │   │   ├── config
│   │   │   │   └── old_configuration
│   │   │   ├── composer-with-laravel-jetstream.json
│   │   │   ├── composer-without-laravel-jetstream.json
│   │   │   ├── composer.json
│   │   │   ├── package-silent.json
│   │   │   └── package.json
│   │   ├── GenerateAppKeyTest.php
│   │   ├── InitializeGitHubRepositoryTest.php
│   │   ├── InitializeGitRepositoryTest.php
│   │   ├── InstallBreezeTest.php
│   │   ├── InstallJetstreamTest.php
│   │   ├── InstallLaravelTest.php
│   │   ├── InstallNpmDependenciesTest.php
│   │   ├── LamboTestEnvironment.php
│   │   ├── MigrateDatabaseTest.php
│   │   ├── OpenInBrowserTest.php
│   │   ├── OpenInEditorTest.php
│   │   ├── PushToGitHubTest.php
│   │   ├── RunAfterScriptTest.php
│   │   ├── SignatureBuilderTest.php
│   │   ├── UpgradeSavedConfigurationTest.php
│   │   ├── ValetLinkTest.php
│   │   ├── ValetSecureTest.php
│   │   ├── ValidateGitHubConfigurationTest.php
│   │   ├── VerifyDependenciesTest.php
│   │   └── VerifyPathAvailableTest.php
│   ├── TestCase.php
│   └── Unit/
│       ├── CommandLineConfigurationTest.php
│       ├── Fakes/
│       │   └── FakeInput.php
│       ├── GetTimezoneTest.php
│       ├── SavedConfigurationTest.php
│       ├── SetConfigTest.php
│       └── ShellConfigurationTest.php
└── tlint.json

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.yml]
indent_style = space
indent_size = 2


================================================
FILE: .gitattributes
================================================
* text=auto
.travis.yml export-ignore


================================================
FILE: .github/workflows/run-tests.yml
================================================
name: Run Tests

on:
  push:
    branches: [ main ]
  pull_request:

jobs:
  tests:
    strategy:
      matrix:
        os: [Ubuntu, macOS]
        php: [8.1, 8.2]

        include:
        - os: Ubuntu
          os-version: ubuntu-latest

        - os: macOS
          os-version: macos-latest

    name: ${{ matrix.os }} - PHP ${{ matrix.php }}

    runs-on: ${{ matrix.os-version }}

    steps:
    - name: Checkout code
      uses: actions/checkout@v1

    - name: Setup PHP
      uses: shivammathur/setup-php@v2
      with:
          php-version: ${{ matrix.php }}
          extensions: posix, dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick
          coverage: none

    - name: Install dependencies
      run: composer update --prefer-stable --prefer-dist --no-interaction --no-suggest

    - name: Run PHP tests
      run: vendor/bin/phpunit


================================================
FILE: .gitignore
================================================
/vendor
.phpunit.result.cache
/storage/framework/
.php_cs.cache


================================================
FILE: .phpcs.xml.dist
================================================
<?xml version="1.0"?>
<ruleset>
   <file>app</file>
   <file>config</file>
   <file>tests</file>

   <rule ref="Tighten"/>
</ruleset>


================================================
FILE: LICENSE.TXT
================================================
The MIT License (MIT)

Copyright (c) <Matt Stauffer>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.


================================================
FILE: app/Actions/AbortsCommands.php
================================================
<?php

namespace App\Actions;

use App\LamboException;

trait AbortsCommands
{
    public function abortIf(bool $abort, string $message, $process = null)
    {
        if ($abort) {
            if ($process) {
                throw new LamboException("{$message}\nFailed to run: '{$process->getCommandLine()}'.");
            }
            throw new LamboException("{$message}");
        }
    }
}


================================================
FILE: app/Actions/Concerns/InteractsWithComposer.php
================================================
<?php

namespace App\Actions\Concerns;

use App\Actions\AbortsCommands;
use App\Shell;

trait InteractsWithComposer
{
    use AbortsCommands;

    protected function composerRequire(string $package, bool $forDev = true): void
    {
        $command = $this->getComposerRequireCommand($package, $forDev);
        $composerProcess = app(Shell::class)->execInProject($command);
        $this->abortIf(! $composerProcess->isSuccessful(), 'Composer package installation failed.', $composerProcess);
    }

    protected function getComposerRequireCommand(string $package, bool $forDev): string
    {
        return sprintf(
            'composer require %s%s%s',
            $package,
            $forDev ? ' --dev' : '',
            config('lambo.store.with_output') ? '' : ' --quiet'
        );
    }
}


================================================
FILE: app/Actions/Concerns/InteractsWithGitHub.php
================================================
<?php

namespace App\Actions\Concerns;

use App\Configuration\LamboConfiguration;
use App\LamboException;

trait InteractsWithGitHub
{
    protected static function shouldCreateRepository(): bool
    {
        return static::gitHubInitializationRequested() && static::gitHubToolingInstalled();
    }

    protected static function gitHubInitializationRequested(): bool
    {
        return config('lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB) === true;
    }

    protected static function getDescription(): string
    {
        $description = config('lambo.store.' . LamboConfiguration::GITHUB_DESCRIPTION);

        if (is_null($description)) {
            return '';
        }

        return sprintf(' --description="%s"', $description);
    }

    protected static function getHomepage(): string
    {
        $homepage = config('lambo.store.' . LamboConfiguration::GITHUB_HOMEPAGE);

        if (is_null($homepage)) {
            return '';
        }

        return sprintf(' --homepage="%s"', $homepage);
    }

    /**
     * @throws LamboException
     */
    protected static function getGitHubCreateCommand(): string
    {
        if (static::ghInstalled()) {
            return sprintf(
                'gh repo create%s --confirm %s%s%s',
                static::getRepositoryName(),
                config('lambo.store.github_public') ? ' --public' : ' --private',
                static::getDescription(),
                static::getHomepage(),
            );
        }

        if (static::hubInstalled()) {
            return sprintf(
                'hub create %s%s%s%s',
                config('lambo.store.github_public') ? '' : '--private ',
                static::getDescription(),
                static::getHomepage(),
                static::getRepositoryName()
            );
        }

        throw new LamboException("Missing tool. Expected one of 'gh' or 'hub' to be installed but none found.");
    }

    protected static function getRepositoryName(): string
    {
        $name = config('lambo.store.project_name');
        $organization = config('lambo.store.' . LamboConfiguration::GITHUB_ORGANIZATION);

        return $organization ? " {$organization}/{$name}" : " {$name}";
    }

    protected static function ghInstalled(): bool
    {
        return config('lambo.store.tools.gh') === true;
    }

    protected static function hubInstalled(): bool
    {
        return config('lambo.store.tools.hub') === true;
    }

    protected static function gitHubToolingInstalled(): bool
    {
        return static::ghInstalled() || static::hubInstalled();
    }
}


================================================
FILE: app/Actions/Concerns/InteractsWithNpm.php
================================================
<?php

namespace App\Actions\Concerns;

use App\Actions\AbortsCommands;
use App\Shell;

trait InteractsWithNpm
{
    use AbortsCommands;

    /**
     * @throws \App\LamboException
     */
    protected function installAndCompileNodeDependencies(): void
    {
        $this->installNodeDependencies();
        $this->compileNodeDependencies();
    }

    /**
     * @throws \App\LamboException
     */
    public function installNodeDependencies(): void
    {
        $process = app(Shell::class)->execInProject('npm install' . (config('lambo.store.with_output') ? '' : ' --silent'));
        $this->abortIf(! $process->isSuccessful(), 'Installation of npm dependencies did not complete successfully', $process);
    }

    /**
     * @throws \App\LamboException
     */
    protected function compileNodeDependencies(): void
    {
        $process = app(Shell::class)->execInProject('npm run build' . (config('lambo.store.with_output') ? '' : ' --silent'));
        $this->abortIf(! $process->isSuccessful(), 'Compilation of project assets did not complete successfully', $process);
    }
}


================================================
FILE: app/Actions/CreateDatabase.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;
use App\Tools\Database;
use PDOException;

class CreateDatabase
{
    use AbortsCommands;

    protected $shell;
    protected $database;
    protected $consoleWriter;

    public function __construct(Shell $shell, Database $database, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->database = $database;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        if (! config('lambo.store.create_database')) {
            return;
        }

        $this->consoleWriter->logStep('Creating database');

        $db_name = config('lambo.store.database_name');

        try {
            $databaseCreated = $this->database
                ->fillFromLamboStore(config('lambo.store'))
                ->create($db_name);

            if (! $databaseCreated) {
                $this->consoleWriter->warn($this->failureToCreateError($db_name));
                return;
            }
        } catch (PDOException $e) {
            $this->consoleWriter->warn($e->getMessage());
            $this->consoleWriter->warn($this->failureToCreateError($db_name));
            return;
        }

        $this->consoleWriter->success("Created a new database '{$db_name}'");
    }

    protected function failureToCreateError(string $db_name): string
    {
        return sprintf(
            "Failed to create database '%s' using credentials <fg=yellow>mysql://%s:****@%s:%s</>\nYou will need to create the database manually.",
            $db_name,
            config('lambo.store.database_username'),
            config('lambo.store.database_host'),
            config('lambo.store.database_port')
        );
    }
}


================================================
FILE: app/Actions/CustomizeDotEnv.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File;

class CustomizeDotEnv
{
    protected $consoleWriter;

    public function __construct(ConsoleWriter $consoleWriter)
    {
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        $this->consoleWriter->logStep('Customizing .env and .env.example');

        $filePath = config('lambo.store.project_path') . '/.env.example';

        $output = $this->customize(File::get($filePath));

        File::put($filePath, $output);
        File::put(str_replace('.env.example', '.env', $filePath), $output);

        $this->consoleWriter->success('.env files configured.');
    }

    public function customize($contents): string
    {
        return collect(explode("\n", $contents))->transform(function ($item) {
            $parts = explode('=', $item, 2);

            // Line doesn't contain an equal sign (=); return without modification
            if (count($parts) < 2) {
                return $item;
            }

            [$envKey, $envVal] = $parts;

            $replace = $this->value($envKey, $envVal);

            return "{$envKey}={$replace}";
        })->implode("\n");
    }

    public function value($key, $fallback)
    {
        $replacements = [
            'APP_NAME' => config('lambo.store.project_name'),
            'APP_URL' => config('lambo.store.project_url'),
            'DB_PORT' => config('lambo.store.database_port'),
            'DB_DATABASE' => config('lambo.store.database_name'),
            'DB_USERNAME' => config('lambo.store.database_username'),
            'DB_PASSWORD' => config('lambo.store.database_password'),
        ];

        return Arr::get($replacements, $key, $fallback);
    }
}


================================================
FILE: app/Actions/DisplayHelpScreen.php
================================================
<?php

namespace App\Actions;

use App\Options;

class DisplayHelpScreen
{
    public function __invoke()
    {
        app('console-writer')->text("\n <comment>Usage:</comment>{$this->createCliStringForCommandUsage()}");
        app('console-writer')->text("\n <comment>Options (lambo new myApplication):</comment>{$this->createCliStringForOptionDescriptions()}");
    }

    public function createCliStringForOptionDescriptions(): string
    {
        return collect((new Options())->all())->reduce(function ($carry, $option) {
            $flag = isset($option['short'])
                ? '-' . $option['short'] . ', --' . $option['long']
                : '    --' . $option['long'];

            $flag .= isset($option['param_description'])
                ? "={$option['param_description']}"
                : '';

            return $carry . sprintf("\n   <info>%-33s</info>%s", $flag, $option['cli_description']);
        });
    }

    private function createCliStringForCommandUsage(): string
    {
        return collect([
            [
                'usage' => 'lambo edit-config [--editor=<editor>]',
                'description' => 'Create or edit your <comment>~/.lambo/config</comment> file',
            ],
            [
                'usage' => 'lambo edit-after [--editor=<editor>]',
                'description' => 'Create or edit your <comment>~/.lambo/after</comment> file',
            ],
            [
                'usage' => 'lambo new myApplication [options]',
                'description' => 'Scaffold a new Laravel application',
            ],
        ])->reduce(function ($carry, $command) {
                return $carry . sprintf("\n   <info>%-40s</info> %s", $command['usage'], $command['description']);
        });
    }
}


================================================
FILE: app/Actions/DisplayLamboWelcome.php
================================================
<?php

namespace App\Actions;

class DisplayLamboWelcome
{
    protected $lamboLogo = '
     __                    __               :version:
    / /   ____ _____ ___  / /_  ____
   / /   / __ `/ __ `__ \/ __ \/ __ \
  / /___/ /_/ / / / / / / /_/ / /_/ /
 /_____/\__,_/_/ /_/ /_/_.___/\____/';

    protected $welcomeText = "
<info>Lambo:</info> Super-powered <comment>'laravel new'</comment> for Laravel and Valet.";

    public function __construct()
    {
        $this->lamboLogo = str_replace(':version:', config('app.version'), $this->lamboLogo);
    }

    public function __invoke()
    {
        foreach (explode("\n", $this->lamboLogo) as $line) {
            // Extra space on the end fixes an issue with console when it ends with backslash
            app('console-writer')->text("<info>{$line} </info>");
        }

        foreach (explode("\n", $this->welcomeText) as $line) {
            // Extra space on the end fixes an issue with console when it ends with backslash
            app('console-writer')->text("{$line} ");
        }
    }
}


================================================
FILE: app/Actions/EditConfigFile.php
================================================
<?php

namespace App\Actions;

use App\Shell;
use Illuminate\Support\Facades\File;

class EditConfigFile
{
    use AbortsCommands;

    public $shell;

    public function __construct(Shell $shell)
    {
        $this->shell = $shell;
    }

    public function __invoke(string $fileName)
    {
        $configDir = config('home_dir') . '/.lambo';
        $configFilePath = $configDir . '/' . $fileName;

        if (! File::isDirectory($configDir)) {
            app('console-writer')->note("Configuration directory '{$configDir}' does not exist, creating it now...");
            $this->abortIf(! File::makeDirectory($configDir), "I could not create the directory: {$configDir}.");
        }

        if (! File::isFile($configFilePath)) {
            app('console-writer')->note("File '{$configFilePath}' does not exist, creating it now...");
            $this->abortIf(! File::put($configFilePath, File::get(base_path("stubs/{$fileName}"))), "I could not create the configuration file: {$configFilePath}.");
        }

        $process = $this->shell->withTTY()->execIn($configDir, config('lambo.store.editor') . " {$fileName}");

        $this->abortIf(! $process->isSuccessful(), "I could not open {$configFilePath} for editing.", $process);
    }
}


================================================
FILE: app/Actions/GenerateAppKey.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;

class GenerateAppKey
{
    use AbortsCommands;

    protected $shell;
    protected $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        $this->consoleWriter->logStep('Setting APP_KEY in .env');

        $process = $this->shell->execInProject("php artisan key:generate{$this->withQuiet()}");

        $this->abortIf(! $process->isSuccessful(), 'Failed to generated APP_KEY successfully', $process);

        $this->consoleWriter->success('APP_KEY has been set.');
    }

    private function withQuiet()
    {
        return config('lambo.store.with_output') ? '' : ' --quiet';
    }
}


================================================
FILE: app/Actions/InitializeGitHubRepository.php
================================================
<?php

namespace App\Actions;

use App\Actions\Concerns\InteractsWithGitHub;
use App\ConsoleWriter;
use App\Shell;

class InitializeGitHubRepository
{
    use AbortsCommands;
    use InteractsWithGitHub;

    public const WARNING_FAILED_TO_CREATE_REPOSITORY = 'Failed to create new GitHub repository';

    protected $shell;
    protected $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        if (! static::gitHubInitializationRequested()) {
            return;
        }

        $this->consoleWriter->logStep('Initializing GitHub repository');

        $process = $this->shell->execInProject(static::getGitHubCreateCommand());

        if (! $process->isSuccessful()) {
            $this->consoleWriter->warn(self::WARNING_FAILED_TO_CREATE_REPOSITORY);
            $this->consoleWriter->warnCommandFailed($process->getCommandLine());
            $this->consoleWriter->showOutputErrors($process->getErrorOutput());
            config(['lambo.store.push_to_github' => false]);

            return;
        }
        config(['lambo.store.push_to_github' => true]);

        $this->consoleWriter->success('Successfully created new GitHub repository');
    }
}


================================================
FILE: app/Actions/InitializeGitRepository.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;

class InitializeGitRepository
{
    use AbortsCommands;

    protected $shell;
    protected $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        $this->consoleWriter->logStep('Initializing git repository');

        $this->exec(sprintf(
            'git init%s',
            config('lambo.store.with_output') ? '' : ' --quiet',
        ));

        $this->exec('git add .');

        $this->exec(sprintf(
            "git commit%s -m '%s'",
            config('lambo.store.with_output') ? '' : ' --quiet',
            config('lambo.store.commit_message')
        ));

        $this->consoleWriter->success('New git repository initialized.');
    }

    public function exec($command)
    {
        $process = $this->shell->execInProject($command);
        $this->abortIf(! $process->isSuccessful(), 'Initialization of git repository did not complete successfully.', $process);
    }
}


================================================
FILE: app/Actions/InstallBreeze.php
================================================
<?php

namespace App\Actions;

use App\Actions\Concerns\InteractsWithComposer;
use App\Actions\Concerns\InteractsWithNpm;
use App\ConsoleWriter;
use App\LamboException;
use App\Shell;

class InstallBreeze
{
    use AbortsCommands;
    use InteractsWithComposer;
    use InteractsWithNpm;

    public const VALID_STACKS = [
        'Blade' => 'blade',
        'Vue' => 'vue',
        'React' => 'react',
    ];

    private $shell;
    private $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        if (($stack = config('lambo.store.breeze')) === false) {
            return;
        }

        if (! in_array($stack, array_values(self::VALID_STACKS), true)) {
            throw new LamboException("'{$stack}' is not a valid Breeze configuration.");
        }

        $this->consoleWriter->logStep('Installing Laravel Breeze starter kit');

        $this->composerRequire('laravel/breeze');
        $this->installBreeze($stack);
        $this->installAndCompileNodeDependencies();

        $this->consoleWriter->success('Successfully installed Laravel Breeze.');
    }

    protected function installBreeze($stack): void
    {
        $process = $this->shell->execInProject(sprintf(
            'php artisan breeze:install%s%s',
            $stack === 'blade' ? '' : " {$stack}",
            config('lambo.store.with_output') ? '' : ' --quiet'
        ));
        $this->abortIf(! $process->isSuccessful(), 'Failed to install Laravel Breeze.', $process);
    }
}


================================================
FILE: app/Actions/InstallJetstream.php
================================================
<?php

namespace App\Actions;

use App\Actions\Concerns\InteractsWithComposer;
use App\Actions\Concerns\InteractsWithNpm;
use App\ConsoleWriter;
use App\LamboException;
use App\Shell;

class InstallJetstream
{
    use AbortsCommands;
    use InteractsWithComposer;
    use InteractsWithNpm;

    public const VALID_CONFIGURATIONS = [
        'inertia',
        'livewire',
        'inertia,teams',
        'livewire,teams',
        'teams,inertia',
        'teams,livewire'
    ];

    public const VALID_STACKS = [
        'Inertia' => 'inertia',
        'Livewire' => 'livewire',
    ];

    private ConsoleWriter $consoleWriter;
    private Shell $shell;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    /**
     * @throws LamboException
     */
    public function __invoke(): void
    {
        if (($stack = config('lambo.store.jetstream')) === false) {
            return;
        }

        if (! in_array($stack, self::VALID_CONFIGURATIONS, true)) {
            throw new LamboException("'{$stack}' is not a valid Jetstream configuration.");
        }

        $this->consoleWriter->logStep('Installing Laravel Jetstream starter kit');

        $this->composerRequire('laravel/jetstream');
        $this->installJetstream($stack);
        $this->installAndCompileNodeDependencies();

        $this->consoleWriter->success('Successfully installed Laravel Jetstream.');
    }

    /**
     * @throws LamboException
     */
    protected function installJetstream(string $stack): void
    {
        $configuration = explode(',', $stack);
        $installJetstreamProcess = $this->shell->execInProject(sprintf(
            'php artisan jetstream:install %s%s%s',
            in_array('livewire', $configuration) ? 'livewire' : 'inertia',
            in_array('teams', $configuration) ? ' --teams' : '',
            config('lambo.store.with_output') ? '' : ' --quiet'
        ));
        $this->abortIf(! $installJetstreamProcess->isSuccessful(), 'Failed to install Laravel Jetstream.', $installJetstreamProcess);
    }
}


================================================
FILE: app/Actions/InstallLaravel.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;

class InstallLaravel
{
    use AbortsCommands;

    protected $shell;
    protected $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        $this->consoleWriter->logStep('Creating the new Laravel project');

        $process = $this->shell->execInRoot(sprintf(
            'composer create-project laravel/laravel %s%s --remove-vcs --prefer-dist %s',
            config('lambo.store.project_name'),
            config('lambo.store.dev') ? ' dev-master' : '',
            config('lambo.store.with_output') ? '' : '--quiet'
        ));

        $this->abortIf(! $process->isSuccessful(), 'The laravel installer did not complete successfully.', $process);

        $this->consoleWriter->success(sprintf(
            "A new application '%s' has been created from the %s branch.",
            config('lambo.store.project_name'),
            config('lambo.store.dev') ? 'develop' : 'release'
        ));
    }
}


================================================
FILE: app/Actions/InstallNpmDependencies.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;

class InstallNpmDependencies
{
    use AbortsCommands;

    protected $shell;
    protected $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        $this->consoleWriter->logStep('Installing node dependencies');

        $process = $this->shell->execInProject("npm install{$this->withQuiet()}");
        $this->abortIf(! $process->isSuccessful(), 'Installation of npm dependencies did not complete successfully', $process);

        $this->consoleWriter->newLine();
        $this->consoleWriter->success('Npm dependencies installed.');
    }

    public function withQuiet()
    {
        return config('lambo.store.with_output') ? '' : ' --silent';
    }
}


================================================
FILE: app/Actions/MigrateDatabase.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;
use App\Tools\Database;
use PDOException;

class MigrateDatabase
{
    use AbortsCommands;

    protected $shell;
    protected $database;
    protected $consoleWriter;

    public function __construct(Shell $shell, Database $database, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->database = $database;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        if (! config('lambo.store.migrate_database')) {
            return;
        }

        $this->consoleWriter->logStep('Running database migrations');

        try {
            $this->database
                ->fillFromLamboStore(config('lambo.store'))
                ->ensureExists(config('lambo.store.database_name'));

            $process = $this->shell->execInProject("php artisan migrate{$this->withQuiet()}");

            return $process->isSuccessful()
                ? $this->consoleWriter->success('Database migrated')
                : $this->consoleWriter->warn("Failed to run {$process->getCommandLine()}");
        } catch (PDOException $e) {
            $this->consoleWriter->warn($e->getMessage());
            return $this->consoleWriter->warn($this->failureMigrateError());
        }
    }

    protected function failureMigrateError(): string
    {
        return sprintf(
            "Skipping database migration using credentials <fg=yellow>mysql://%s:****@%s:%s</>\nYou will need to run the database migrations manually.",
            config('lambo.store.database_username'),
            config('lambo.store.database_host'),
            config('lambo.store.database_port')
        );
    }

    private function withQuiet()
    {
        return config('lambo.store.with_output') ? '' : ' --quiet';
    }
}


================================================
FILE: app/Actions/OpenInBrowser.php
================================================
<?php

namespace App\Actions;

use App\Environment;
use App\Shell;

class OpenInBrowser
{
    use AbortsCommands;

    protected $shell;
    protected $consoleWriter;
    protected $environment;

    public function __construct(Shell $shell, Environment $environment)
    {
        $this->shell = $shell;
        $this->environment = $environment;
    }

    public function __invoke()
    {
        if (config('lambo.store.no_browser')) {
            return;
        }

        app('console-writer')->logStep('Opening in Browser');

        if ($this->environment->isMac() && $this->browser()) {
            $this->shell->execInProject(sprintf(
                'open -a "%s" "%s"',
                $this->browser(),
                config('lambo.store.project_url')
            ));

            return;
        }

        $this->shell->execInProject('valet open');
    }

    public function browser()
    {
        return config('lambo.store.browser');
    }
}


================================================
FILE: app/Actions/OpenInEditor.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;

class OpenInEditor
{
    use AbortsCommands;

    protected $shell;
    protected $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        $this->consoleWriter->logStep('Opening In Editor');

        $process = $this->shell->withTTY()->execInProject(sprintf('%s .', config('lambo.store.editor')));
        $this->abortIf(! $process->isSuccessful(), sprintf('Failed to open editor %s', config('lambo.store.editor')), $process);

        $this->consoleWriter->success('Opening your project in ' . config('lambo.store.editor'));
    }
}


================================================
FILE: app/Actions/PushToGitHub.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;

class PushToGitHub
{
    public const WARNING_FAILED_TO_PUSH = 'Failed to push project to GitHub.';
    public const WARNING_UNABLE_TO_GET_BRANCH_NAME = self::WARNING_FAILED_TO_PUSH . ' Unable to determine git branch name.';

    protected $shell;
    protected $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        if (! (config('lambo.store.push_to_github'))) {
            return;
        }

        $this->consoleWriter->logStep('Pushing new project to GitHub');

        $branchNameProcess = $this->shell->execInProject('git rev-parse --abbrev-ref HEAD');
        if (! $branchNameProcess->isSuccessful()) {
            $this->consoleWriter->warn(self::WARNING_UNABLE_TO_GET_BRANCH_NAME);
            $this->consoleWriter->warn("Failed to run {$branchNameProcess->getCommandLine()}");
            $this->consoleWriter->showOutputErrors($branchNameProcess->getErrorOutput());
            return;
        }

        $process = $this->shell->execInProject("git push -u origin {$branchNameProcess->getOutput()}");
        if (! $process->isSuccessful()) {
            $this->consoleWriter->warn(self::WARNING_FAILED_TO_PUSH);
            $this->consoleWriter->warn("Failed to run {$process->getCommandLine()}");
            $this->consoleWriter->showOutputErrors($process->getErrorOutput());
            return;
        }

        $this->consoleWriter->success('Successfully pushed project to GitHub');
    }
}


================================================
FILE: app/Actions/RunAfterScript.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;
use Illuminate\Support\Facades\File;

class RunAfterScript
{
    use AbortsCommands;

    protected $shell;
    protected $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        $afterScriptPath = config('home_dir') . '/.lambo/after';
        if (! File::isFile($afterScriptPath)) {
            return;
        }

        $this->consoleWriter->logStep('Running after script');

        $this->shell->withTTY();
        $process = $this->shell->execInProject(sprintf(
            'env PROJECTPATH=%s sh %s',
            config('lambo.store.project_path'),
            $afterScriptPath
        ));
        $this->abortIf(! $process->isSuccessful(), 'After file did not complete successfully', $process);

        $this->consoleWriter->success('After script has completed.');
    }
}


================================================
FILE: app/Actions/UpgradeSavedConfiguration.php
================================================
<?php

namespace App\Actions;

use Carbon\Carbon;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;

class UpgradeSavedConfiguration
{
    // IMPORTANT NOTE: Every time we make *any* changes to configuration, we need
    // to increment this configurationVersion so that users get upgraded config
    private $configurationVersion = 1;
    private $configDir;
    private $configFilePath;
    private $lastVersionUpdateFilePath;
    private $commented = [];
    private $removedConfigurationKeys = [
        'NODE',
        'MIX',
        'AUTH',
        'FRONTEND',
    ];
    private $newConfiguration = [
        'MIGRATE_DATABASE' => [
            'commented' => false,
            'default' => 'false',
            'description' => [
                'Run the standard Laravel database migrations.',
                'Possible values:',
                '  true, 1, "yes" or "on"',
                '  false (default), 0, "no" or "off"',
            ],
        ],
        'DB_HOST' => [
            'commented' => true,
            'default' => '127.0.0.1',
            'description' => [
                'The database host. Defaults to 127.0.0.1.',
            ],
        ],
        'DB_PORT' => [
            'commented' => true,
            'default' => '',
            'description' => [
                'The database port. Defaults to 3306.',
            ],
        ],
        'DB_NAME' => [
            'commented' => true,
            'default' => '',
            'description' => [
                'The database name. Defaults to the project name.',
            ],
        ],
    ];

    public function __construct()
    {
        $this->configDir = config('home_dir') . '/.lambo';
        $this->configFilePath = "{$this->configDir}/config";
        $this->lastVersionUpdateFilePath = "{$this->configDir}/.last_version_update";
    }

    public function __invoke(): bool
    {
        if (! $this->shouldUpgrade()) {
            return false;
        }

        $savedConfiguration = File::get($this->configFilePath);
        File::move($this->configFilePath, $this->configFilePath . '.' . Carbon::now()->toDateTimeLocalString());

        File::put($this->configFilePath, $this->upgrade($savedConfiguration, $this->removedConfigurationKeys, $this->newConfiguration));

        File::delete($this->lastVersionUpdateFilePath);
        File::put($this->lastVersionUpdateFilePath, $this->configurationVersion);

        return true;
    }

    public function upgrade(string $savedConfiguration, array $removedConfigurationKeys, array $newConfiguration = []): string
    {
        return implode(PHP_EOL, [
            $this->commentRemovedConfiguration($savedConfiguration, $removedConfigurationKeys),
            "\n# ------------------------------------------------------------------------------",
            '# ' . Carbon::now(config('app.timezone'))->format('j-M-Y g:i a') . ' (auto-generated by Lambo):',
            '# ------------------------------------------------------------------------------',
            $this->summarizeComments(),
            $this->addNewConfiguration($newConfiguration),
        ]);
    }

    private function shouldUpgrade(): bool
    {
        if (! File::isFile($this->configFilePath)) {
            return false;
        }

        $localVersion = File::isFile($this->lastVersionUpdateFilePath)
            ? (int)File::get($this->lastVersionUpdateFilePath)
            : 0;

        if ($localVersion < $this->configurationVersion) {
            return true;
        }

        return false;
    }

    private function commentRemovedConfiguration(string $savedConfiguration, array $oldConfigurationKeys): string
    {
        return collect(explode("\n", $savedConfiguration))->transform(function ($item) use ($oldConfigurationKeys) {
            $matched = collect($oldConfigurationKeys)->reduce(function ($carry, $oldKey) use ($item) {
                return $carry || Str::of($item)->startsWith($oldKey);
            }, false);
            if ($matched) {
                $this->commented[] = $item;
                return "#{$item}";
            }
            return $item;
        })->implode("\n");
    }

    private function summarizeComments(): string
    {
        if (count($this->commented) < 1) {
            return '';
        }

        return implode(PHP_EOL, [
            '# Lambo has commented out the following configuration items as they',
            '# are no-longer used. You may safely remove them:',
            collect($this->commented)->reduce(function ($carry, $item) {
                return "{$carry}#   {$item}\n";
            }, '')
        ]);
    }

    private function addNewConfiguration(array $newConfiguration): string
    {
        if (count($newConfiguration) < 1) {
            return '';
        }

        return collect(array_keys($newConfiguration))->reduce(function ($carry, $key) use ($newConfiguration) {
            $description = collect($newConfiguration[$key]['description'])->reduce(function ($carry, $item) {
                return "{$carry}# {$item}\n";
            }, '');

            $configurationItem = sprintf(
                "%s%s=%s\n\n",
                $newConfiguration[$key]['commented'] ? '#' : '',
                $key,
                $newConfiguration[$key]['default']
            );

            return "{$carry}{$description}{$configurationItem}";
        }, "# Lambo has introduced new configuration options. They have been added here\n# with sensible defaults; however, you should review them.\n#\n");
    }
}


================================================
FILE: app/Actions/ValetLink.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;

class ValetLink
{
    use AbortsCommands;

    protected $shell;

    private $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        if (! config('lambo.store.valet_link')) {
            return;
        }

        $this->consoleWriter->logStep('Running valet link');

        $process = $this->shell->execInProject('valet link');
        $this->abortIf(! $process->isSuccessful(), 'valet link did not complete successfully', $process);

        $this->consoleWriter->success('valet link successful');
    }
}


================================================
FILE: app/Actions/ValetSecure.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use App\Shell;

class ValetSecure
{
    use AbortsCommands;

    protected $shell;
    protected $consoleWriter;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->shell = $shell;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        if (! config('lambo.store.valet_secure')) {
            return;
        }

        $this->consoleWriter->logStep('Running valet secure');

        $process = $this->shell->execInProject('valet secure');
        $this->abortIf(! $process->isSuccessful(), 'valet secure did not complete successfully', $process);

        $this->consoleWriter->success('valet secure successful');
    }
}


================================================
FILE: app/Actions/ValidateGitHubConfiguration.php
================================================
<?php

namespace App\Actions;

use App\Actions\Concerns\InteractsWithGitHub;
use App\Configuration\LamboConfiguration;
use App\ConsoleWriter;
use App\Shell;

class ValidateGitHubConfiguration
{
    use InteractsWithGitHub;

    public const WARNING_UNABLE_TO_CREATE_REPOSITORY = 'Unable to create a new GitHub repository';
    public const INSTRUCTIONS_GITHUB_TOOLING_MISSING = [
        'For Lambo to initialize a new repository on GitHub it requires either the',
        'official GitHub command line tool or the unofficial hub tool, but neither',
        'are installed. You can find more information about each tool by visiting:',
        '    - <fg=blue;options=underscore>https://github.com/cli/cli#installation</>',
        '    - <fg=blue;options=underscore>https://github.com/github/hub</>',
    ];
    public const INSTRUCTIONS_GH_NOT_AUTHENTICATED = [
        'You are not logged into GitHub. Please run <comment>gh auth login</comment>.',
        'For more information, please visit, <fg=blue;options=underscore>https://cli.github.com/manual/gh_auth_login</>',
    ];
    public const QUESTION_SHOULD_CONTINUE = 'Would you like Lambo to continue without GitHub repository creation?';
    public const SELECTED_GITHUB_TOOL_MESSAGE_PATTERN = "Using the '%s' command for GitHub configuration.";

    private $consoleWriter;
    private $shell;

    public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    {
        $this->consoleWriter = $consoleWriter;
        $this->shell = $shell;
    }

    public function __invoke()
    {
        if (! static::gitHubInitializationRequested()) {
            config(['lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB => false]);
            return;
        }

        if (! static::gitHubToolingInstalled()) {
            $this->consoleWriter->warn(self::WARNING_UNABLE_TO_CREATE_REPOSITORY);
            $this->consoleWriter->text(self::INSTRUCTIONS_GITHUB_TOOLING_MISSING);
            $this->askToContinueWithoutGitHubSetup();
            return;
        }

        if (static::hubInstalled()) {
            $this->consoleWriter->note(sprintf(self::SELECTED_GITHUB_TOOL_MESSAGE_PATTERN, 'hub'));
            return;
        }

        if (! $this->ghAuthenticated()) {
            $this->consoleWriter->warn(self::WARNING_UNABLE_TO_CREATE_REPOSITORY);
            $this->consoleWriter->text(self::INSTRUCTIONS_GH_NOT_AUTHENTICATED);
            $this->askToContinueWithoutGitHubSetup();
            return;
        }

        $this->consoleWriter->note(sprintf(self::SELECTED_GITHUB_TOOL_MESSAGE_PATTERN, 'gh'));
    }

    private function askToContinueWithoutGitHubSetup()
    {
        config(['lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB => false]);

        if (! app('console')->confirm(self::QUESTION_SHOULD_CONTINUE)) {
            exit;
        }
    }

    private function ghAuthenticated(): bool
    {
        $process = $this->shell->execQuietly('gh auth status');

        return $process->isSuccessful();
    }
}


================================================
FILE: app/Actions/VerifyDependencies.php
================================================
<?php

namespace App\Actions;

use App\ConsoleWriter;
use Symfony\Component\Process\ExecutableFinder;

class VerifyDependencies
{
    use AbortsCommands;

    protected $finder;
    protected $consoleWriter;

    private $dependencies = [
        [
            'command' => 'composer',
            'label' => 'Composer',
            'instructions_url' => 'https://getcomposer.org',
        ],
        [
            'command' => 'valet',
            'label' => 'Laravel valet',
            'instructions_url' => 'https://laravel.com/docs/valet',
        ],
        [
            'command' => 'git',
            'label' => 'Git version control',
            'instructions_url' => 'https://git-scm.com',
        ],
    ];

    private $optionalDependencies = [
        [
            'command' => 'hub',
            'label' => 'Unofficial GitHub command line tool',
            'instructions_url' => 'https://github.com/github/hub',
        ],
        [
            'command' => 'gh',
            'label' => 'Official GitHub command line tool',
            'instructions_url' => 'https://cli.github.com/',
        ],
    ];

    public function __construct(ExecutableFinder $finder, ConsoleWriter $consoleWriter)
    {
        $this->finder = $finder;
        $this->consoleWriter = $consoleWriter;
    }

    public function __invoke()
    {
        $this->consoleWriter->logStep('Verifying dependencies');

        $this->consoleWriter->text('Optional dependencies');
        $this->consoleWriter->newLine();

        foreach ($this->optionalDependencies as $optionalDependency) {
            list($command, $label, $instructionsUrl) = array_values($optionalDependency);

            if (($installedDependency = $this->finder->find($command)) === null) {
                $this->consoleWriter->note("{$label}, an optional dependency, is missing. You can find installation instructions at:\n        <fg=blue;href={$instructionsUrl}>{$instructionsUrl}</>");
                config(["lambo.store.tools.{$command}" => false]);
            } else {
                $this->consoleWriter->success("{$label} found at:\n        <fg=blue>{$installedDependency}</>");
                config(["lambo.store.tools.{$command}" => true]);
            }
        }

        $this->consoleWriter->newLine();
        $this->consoleWriter->text('Required dependencies');
        $this->consoleWriter->newLine();
        $this->abortIf(
            collect($this->dependencies)->reduce(function ($carry, $dependency) {
                list($command, $label, $instructionsUrl) = array_values($dependency);
                if (($installedDependency = $this->finder->find($command)) === null) {
                    $this->consoleWriter->warn("{$label} is missing. You can find installation instructions at:\n        <fg=blue;href={$instructionsUrl}>{$instructionsUrl}</>");
                    return true;
                }
                $this->consoleWriter->success("{$label} found at:\n        <fg=blue>{$installedDependency}</>");
                return $carry ?? false;
            }),
            'Please install missing dependencies and try again.'
        );
    }
}


================================================
FILE: app/Actions/VerifyPathAvailable.php
================================================
<?php

namespace App\Actions;

use App\LamboException;
use Illuminate\Support\Facades\File;

class VerifyPathAvailable
{
    use AbortsCommands;

    private $consoleWriter;

    public function __invoke()
    {
        app('console-writer')->logStep('Verifying path availability');

        $rootPath = config('lambo.store.root_path');

        if (! File::isDirectory($rootPath)) {
            throw new LamboException("{$rootPath} is not a directory.");
        }

        $projectPath = config('lambo.store.project_path');

        if (empty($projectPath)) {
            throw new LamboException("Configuration 'lambo.store.project_path' cannot be null or an empty string.");
        }

        if (File::isDirectory($projectPath)) {
            if (! config('lambo.store.force_create')) {
                throw new LamboException("{$projectPath} is already a directory.");
            }

            if (! File::deleteDirectory($projectPath)) {
                throw new LamboException("{$projectPath} is already a directory and, although the force option was specified, deletion failed.");
            }
        }

        app('console-writer')->success("Directory '{$projectPath}' is available.");
    }
}


================================================
FILE: app/Commands/.gitkeep
================================================


================================================
FILE: app/Commands/Debug.php
================================================
<?php

namespace App\Commands;

use App\ConsoleWriter;
use Carbon\Carbon;
use Dotenv\Dotenv;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File;
use IntlTimeZone;

trait Debug
{
    protected function arrayToTable(array $data, array $filter = null, string $keyPrefix = '', array $headers = null): void
    {
        if (empty($data)) {
            return;
        }

        $rows = collect($data)
            ->filter(function ($value, $key) use ($filter) {
                return is_null($filter) || in_array($key, $filter);
            })
            ->map(function ($value, $key) use ($keyPrefix) {
                $type = gettype($value);

                if (is_string($value)) {
                    $value =  empty($value)
                        ? ConsoleWriter::formatString('""', ConsoleWriter::BLUE)
                        : ConsoleWriter::formatString($value, ConsoleWriter::BLUE);
                }

                if (is_integer($value)) {
                    $value =  ConsoleWriter::formatString($value, ConsoleWriter::MAGENTA);
                }

                if (is_bool($value)) {
                    $value =  $value
                        ? ConsoleWriter::formatString('true', ConsoleWriter::GREEN)
                        : ConsoleWriter::formatString('false', ConsoleWriter::RED);
                }

                if (is_null($value)) {
                    $value = '';
                }

                return [$keyPrefix . $key, "({$type})", $value];
            })->values()->toArray();

        $this->consoleWriter->table($headers ?: ['key', 'type', 'value'], $rows);
    }

    protected function debugReport(): void
    {
        $this->consoleWriter->panel('Debug', 'Start', 'fg=black;bg=white');

        $this->consoleWriter->sectionTitle('Computed configuration');
        $this->consoleWriter->text([
            'The following is the configuration lambo has computed by merging:',
        ]);
        $this->consoleWriter->listing([
            'command line parameters',
            'saved configuration',
            'shell environment variables.',
        ]);

        $this->configToTable();

        $this->consoleWriter->sectionTitle('Pre-flight Configuration');

        $this->consoleWriter->newLine();
        $this->consoleWriter->text('Raw commmand line:');
        $this->arrayToTable(
            $_SERVER['argv'],
        );

        $this->consoleWriter->text('Command line arguments:');
        $this->arrayToTable($this->arguments());

        $this->consoleWriter->text('Command line options:');
        $this->arrayToTable(
            $this->options(),
            [
                'editor',
                'path',
                'message',
                'github',
                'gh-public',
                'gh-description',
                'gh-homepage',
                'gh-org',
                'breeze',
                'jetstream',
                'browser',
                'dbhost',
                'dbport',
                'dbname',
                'dbuser',
                'dbpassword',
                'create-db',
                'migrate-db',
                'force',
                'link',
                'secure',
                'quiet',
                'dev',
                'full',
                'projectName',
            ],
            '--'
        );

        $this->consoleWriter->text('Saved configuration:');

        $savedConfig = [];
        if (File::isFile(config('home_dir') . '/.lambo/config')) {
            $savedConfig = Dotenv::createMutable(config('home_dir') . '/.lambo', 'config')->load();
        }
        $this->arrayToTable(
            $savedConfig,
            [
                'CODEEDITOR',
                'MESSAGE',
                'PROJECTPATH',
                'BROWSER',
                'FRONTEND',
                'DB_PORT',
                'DB_NAME',
                'DB_USERNAME',
                'DB_PASSWORD',
                'CREATE_DATABASE',
                'LINK',
                'SECURE',
                'QUIET',
                'WITH_OUTPUT',
                'DEVELOP',
                'FULL',
                'WITH_TEAMS',
            ]
        );

        $this->consoleWriter->text('Shell environment variables:');
        $this->arrayToTable($_SERVER, ['EDITOR'], '$');

        $this->logTimezoneData();

        $this->consoleWriter->panel('Debug', 'End', 'fg=black;bg=white');
    }

    protected function configToTable(): void
    {
        $config = Arr::prepend(config('lambo.store'), config('home_dir'), 'home_dir');
        $this->arrayToTable($this->dotFlatten('lambo.store', $config));
    }

    private function dotFlatten($prefix, $array): array
    {
        $result = [];
        foreach ($array as $key => $value) {
            if (is_array($value)) {
                $result = array_merge($result, $this->dotFlatten($prefix . '.' . $key, $value));
            } else {
                $result[$prefix . '.' . $key] = $value;
            }
        }
        return $result;
    }

    protected function logTimezoneData()
    {
        $this->consoleWriter->sectionTitle('Timezone configuration');
        $this->consoleWriter->newLine();
        $this->consoleWriter->text('System settings');
        $this->arrayToTable([
            'OS Config ("/etc/localtime")' => exec('/bin/ls -l /etc/localtime|/usr/bin/cut -d"/" -f8-'),
            "ini_get('date.timezone')" => ini_get('date.timezone') ?: 'Not configured',
            'IntlTimeZone::createDefault()' => IntlTimeZone::createDefault()->getID(),
            'date_default_timezone_get()' => date_default_timezone_get(),
            'config->get("app.timezone")' => config()->get('app.timezone'),
        ]);

        $this->consoleWriter->text('Carbon');
        $this->arrayToTable([
            // UTC, GMT, Atlantic/Azores
            'Carbon (Timezone identifier)' => Carbon::now()->format('e'),

            // 1 if Daylight Saving Time, 0 otherwise.
            'Carbon (Daylight savings)' => (bool)Carbon::now()->format('I'),

            // Difference to Greenwich time (GMT)
            'Carbon (Difference to GMT w/O)' => Carbon::now()->format('O'), // +0200'Carbon (Difference to GMT w/P)' => Carbon::now()->format('P'), // +02:00

            // Examples: EST, MDT
            'Carbon (tz abbreviation)' => Carbon::now()->format('T'),
        ]);
    }
}


================================================
FILE: app/Commands/EditAfter.php
================================================
<?php

namespace App\Commands;

use App\Actions\EditConfigFile;
use App\Configuration\CommandLineConfiguration;
use App\Configuration\LamboConfiguration;
use App\Configuration\SavedConfiguration;
use App\Configuration\SetConfig;
use App\Configuration\ShellConfiguration;
use App\LamboException;

class EditAfter extends LamboCommand
{
    protected $signature = 'edit-after {--editor= : Open the config file in the specified <info>EDITOR</info> or the system default if none is specified.}';

    protected $description = 'Edit Config File. A new config file is created if one does not already exist.';

    public function handle()
    {
        app()->bind('console', function () {
            return $this;
        });

        $commandLineConfiguration = new CommandLineConfiguration([
            'editor' => LamboConfiguration::EDITOR,
        ]);

        $savedConfiguration = new SavedConfiguration([
            'CODEEDITOR' => LamboConfiguration::EDITOR,
        ]);

        $shellConfiguration = new ShellConfiguration([
            'EDITOR' => LamboConfiguration::EDITOR,
        ]);

        (new SetConfig(
            $commandLineConfiguration,
            $savedConfiguration,
            $shellConfiguration,
            app('console-writer'),
            $this->input
        ))([
            LamboConfiguration::EDITOR => 'nano',
        ]);

        try {
            app(EditConfigFile::class)('after');
        } catch (LamboException $e) {
            app('console-writer')->exception($e->getMessage());
        }
    }
}


================================================
FILE: app/Commands/EditConfig.php
================================================
<?php

namespace App\Commands;

use App\Actions\EditConfigFile;
use App\Configuration\CommandLineConfiguration;
use App\Configuration\LamboConfiguration;
use App\Configuration\SavedConfiguration;
use App\Configuration\SetConfig;
use App\Configuration\ShellConfiguration;
use App\LamboException;

class EditConfig extends LamboCommand
{
    protected $signature = 'edit-config {--editor= : Open the config file in the specified <info>EDITOR</info> or the system default if none is specified.}';

    protected $description = 'Edit Config File. A new config file is created if one does not already exist.';

    public function handle()
    {
        app()->bind('console', function () {
            return $this;
        });

        $commandLineConfiguration = new CommandLineConfiguration([
            'editor' => LamboConfiguration::EDITOR,
        ]);

        $savedConfiguration = new SavedConfiguration([
            'CODEEDITOR' => LamboConfiguration::EDITOR,
        ]);

        $shellConfiguration = new ShellConfiguration([
            'EDITOR' => LamboConfiguration::EDITOR,
        ]);

        (new SetConfig(
            $commandLineConfiguration,
            $savedConfiguration,
            $shellConfiguration,
            app('console-writer'),
            $this->input
        ))([
            LamboConfiguration::EDITOR => 'nano',
        ]);

        try {
            app(EditConfigFile::class)('config');
        } catch (LamboException $e) {
            app('console-writer')->exception($e->getMessage());
        }
    }
}


================================================
FILE: app/Commands/HelpCommand.php
================================================
<?php

namespace App\Commands;

use App\Actions\DisplayHelpScreen;
use App\Actions\DisplayLamboWelcome;

class HelpCommand extends LamboCommand
{
    protected $signature = 'help-screen';
    protected $description = 'Show help';

    public function handle()
    {
        app(DisplayLamboWelcome::class)();
        app(DisplayHelpScreen::class)();
    }
}


================================================
FILE: app/Commands/LamboCommand.php
================================================
<?php

namespace App\Commands;

use App\ConsoleWriter;
use LaravelZero\Framework\Commands\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

abstract class LamboCommand extends Command
{
    public function run(InputInterface $input, OutputInterface $output): int
    {
        app()->singleton(ConsoleWriter::class, function () use ($input, $output) {
            return new ConsoleWriter($input, $output);
        });

        app()->alias(ConsoleWriter::class, 'console-writer');

        return parent::run($input, $output);
    }
}


================================================
FILE: app/Commands/NewCommand.php
================================================
<?php

namespace App\Commands;

use App\Actions\CreateDatabase;
use App\Actions\CustomizeDotEnv;
use App\Actions\DisplayHelpScreen;
use App\Actions\DisplayLamboWelcome;
use App\Actions\EditConfigFile;
use App\Actions\GenerateAppKey;
use App\Actions\InitializeGitHubRepository;
use App\Actions\InitializeGitRepository;
use App\Actions\InstallBreeze;
use App\Actions\InstallJetstream;
use App\Actions\InstallLaravel;
use App\Actions\MigrateDatabase;
use App\Actions\OpenInBrowser;
use App\Actions\OpenInEditor;
use App\Actions\PushToGitHub;
use App\Actions\RunAfterScript;
use App\Actions\UpgradeSavedConfiguration;
use App\Actions\ValetLink;
use App\Actions\ValetSecure;
use App\Actions\ValidateGitHubConfiguration;
use App\Actions\VerifyDependencies;
use App\Actions\VerifyPathAvailable;
use App\Configuration\CommandLineConfiguration;
use App\Configuration\LamboConfiguration;
use App\Configuration\SavedConfiguration;
use App\Configuration\SetConfig;
use App\Configuration\ShellConfiguration;
use App\ConsoleWriter;
use App\LamboException;
use App\Options;

class NewCommand extends LamboCommand
{
    use Debug;

    protected $signature;
    protected $description = 'Creates a fresh Laravel application';
    protected $consoleWriter;

    public function __construct()
    {
        $this->signature = $this->buildSignature();

        parent::__construct();

        app()->bind('console', function () {
            return $this;
        });
    }

    public function buildSignature()
    {
        return collect((new Options())->all())->reduce(
            function ($carry, $option) {
                return $carry . $this->buildSignatureOption($option);
            },
            "new\n{projectName? : Name of the Laravel project}"
        );
    }

    public function buildSignatureOption($option): string
    {
        $commandlineOption = isset($option['short']) ? ($option['short'] . '|' . $option['long']) : $option['long'];

        if (isset($option['param_description'])) {
            $commandlineOption .= '=' . ($option['default'] ?? '');
        }

        return "\n{--{$commandlineOption} : {$option['cli_description']}}";
    }

    public function handle()
    {
        app(DisplayLamboWelcome::class)();

        if (! $this->argument('projectName')) {
            app(DisplayHelpScreen::class)();
            exit;
        }

        $this->setConsoleWriter();
        $this->setConfig();

        if (app(UpgradeSavedConfiguration::class)()) {
            $this->consoleWriter->newLine();
            $this->consoleWriter->note('Your Lambo configuration (~/.lambo/config) has been updated.');
            $this->consoleWriter->note('Please review the changes then run lambo again.');
            if ($this->confirm(sprintf('Review the changes now in %s?', config('lambo.store.editor')))) {
                app(EditConfigFile::class)('config');
            }
            return;
        }

        $this->consoleWriter->sectionTitle("Creating a new Laravel app '{$this->argument('projectName')}'");

        try {
            app(VerifyDependencies::class)();
            app(ValidateGitHubConfiguration::class)();
            app(VerifyPathAvailable::class)();
            app(InstallLaravel::class)();
            app(CustomizeDotEnv::class)();
            app(GenerateAppKey::class)();
            app(InstallBreeze::class)();
            app(InstallJetstream::class)();
            app(CreateDatabase::class)();
            app(MigrateDatabase::class)();
            app(InitializeGitRepository::class)();
            app(RunAfterScript::class)();
            app(InitializeGitHubRepository::class)();
            app(PushToGitHub::class)();
            app(ValetLink::class)();
            app(ValetSecure::class)();
            app(OpenInEditor::class)();
            app(OpenInBrowser::class)();
        } catch (LamboException $e) {
            $this->consoleWriter->exception($e->getMessage());
            exit;
        }

        $this->consoleWriter->newLine();
        $this->consoleWriter->text([
            '<fg=green>Done, happy coding!</>',
            'Lambo is brought to you by the lovely folks at <fg=blue;href=https://tighten.co/>Tighten</>.',
        ]);
        $this->consoleWriter->newLine();
    }

    protected function setConsoleWriter()
    {
        $this->consoleWriter = app(ConsoleWriter::class);
    }

    private function setConfig(): void
    {
        config(['lambo.store' => []]); // @todo remove if debug code is removed.

        $commandLineConfiguration = new CommandLineConfiguration([
            'editor' => LamboConfiguration::EDITOR,
            'message' => LamboConfiguration::COMMIT_MESSAGE,
            'path' => LamboConfiguration::ROOT_PATH,
            'browser' => LamboConfiguration::BROWSER,
            'frontend' => LamboConfiguration::FRONTEND_FRAMEWORK,
            'dbhost' => LamboConfiguration::DATABASE_HOST,
            'dbport' => LamboConfiguration::DATABASE_PORT,
            'dbname' => LamboConfiguration::DATABASE_NAME,
            'dbuser' => LamboConfiguration::DATABASE_USERNAME,
            'dbpassword' => LamboConfiguration::DATABASE_PASSWORD,
            'create-db' => LamboConfiguration::CREATE_DATABASE,
            'force' => LamboConfiguration::FORCE_CREATE,
            'migrate-db' => LamboConfiguration::MIGRATE_DATABASE,
            'link' => LamboConfiguration::VALET_LINK,
            'secure' => LamboConfiguration::VALET_SECURE,
            'with-output' => LamboConfiguration::WITH_OUTPUT,
            'dev' => LamboConfiguration::USE_DEVELOP_BRANCH,
            'full' => LamboConfiguration::FULL,
            'github' => LamboConfiguration::INITIALIZE_GITHUB,
            'gh-public' => LamboConfiguration::GITHUB_PUBLIC,
            'gh-description' => LamboConfiguration::GITHUB_DESCRIPTION,
            'gh-homepage' => LamboConfiguration::GITHUB_HOMEPAGE,
            'gh-org' => LamboConfiguration::GITHUB_ORGANIZATION,
            'projectName' => LamboConfiguration::PROJECT_NAME,
            'breeze' => LamboConfiguration::BREEZE,
            'jetstream' => LamboConfiguration::JETSTREAM,
        ]);

        $savedConfiguration = new SavedConfiguration([
            'PROJECTPATH' => LamboConfiguration::ROOT_PATH,
            'MESSAGE' => LamboConfiguration::COMMIT_MESSAGE,
            'DEVELOP' => LamboConfiguration::USE_DEVELOP_BRANCH,
            'CODEEDITOR' => LamboConfiguration::EDITOR,
            'BROWSER' => LamboConfiguration::BROWSER,
            'DB_HOST' => LamboConfiguration::DATABASE_HOST,
            'DB_PORT' => LamboConfiguration::DATABASE_PORT,
            'DB_NAME' => LamboConfiguration::DATABASE_NAME,
            'DB_USERNAME' => LamboConfiguration::DATABASE_USERNAME,
            'DB_PASSWORD' => LamboConfiguration::DATABASE_PASSWORD,
            'CREATE_DATABASE' => LamboConfiguration::CREATE_DATABASE,
            'MIGRATE_DATABASE' => LamboConfiguration::MIGRATE_DATABASE,
            'LINK' => LamboConfiguration::VALET_LINK,
            'SECURE' => LamboConfiguration::VALET_SECURE,
        ]);

        $shellConfiguration = new ShellConfiguration([
            'EDITOR' => LamboConfiguration::EDITOR,
        ]);

        (new SetConfig(
            $commandLineConfiguration,
            $savedConfiguration,
            $shellConfiguration,
            $this->consoleWriter,
            $this->input
        ))([
            LamboConfiguration::COMMAND => self::class,
            LamboConfiguration::EDITOR => 'nano',
            LamboConfiguration::COMMIT_MESSAGE => 'Initial commit',
            LamboConfiguration::ROOT_PATH => getcwd(),
            LamboConfiguration::BROWSER => null,
            LamboConfiguration::DATABASE_HOST => '127.0.0.1',
            LamboConfiguration::DATABASE_PORT => 3306,
            LamboConfiguration::DATABASE_NAME => $this->argument('projectName'),
            LamboConfiguration::DATABASE_USERNAME => 'root',
            LamboConfiguration::DATABASE_PASSWORD => '',
            LamboConfiguration::CREATE_DATABASE => false,
            LamboConfiguration::FORCE_CREATE => false,
            LamboConfiguration::MIGRATE_DATABASE => false,
            LamboConfiguration::VALET_LINK => false,
            LamboConfiguration::VALET_SECURE => false,
            LamboConfiguration::WITH_OUTPUT => false,
            LamboConfiguration::USE_DEVELOP_BRANCH => false,
            LamboConfiguration::FULL => false,
            LamboConfiguration::INITIALIZE_GITHUB => false,
            LamboConfiguration::GITHUB_PUBLIC => false,
            LamboConfiguration::PROJECT_NAME => null,
            LamboConfiguration::GITHUB_DESCRIPTION => null,
            LamboConfiguration::GITHUB_HOMEPAGE => null,
            LamboConfiguration::GITHUB_ORGANIZATION => null,
            LamboConfiguration::BREEZE => false,
            LamboConfiguration::JETSTREAM => false,
            LamboConfiguration::TLD => null,
        ]);

        if ($this->consoleWriter->isDebug()) {
            $this->debugReport();
        }
    }
}


================================================
FILE: app/Configuration/CommandLineConfiguration.php
================================================
<?php

namespace App\Configuration;

class CommandLineConfiguration extends LamboConfiguration
{
    protected function getSettings(): array
    {
        $commandLineConfiguration = app('console')->options();

        foreach (app('console')->arguments() as $key => $value) {
            $commandLineConfiguration[$key] = $value;
        }

        return $commandLineConfiguration;
    }
}


================================================
FILE: app/Configuration/LamboConfiguration.php
================================================
<?php

namespace App\Configuration;

use Illuminate\Support\Str;

abstract class LamboConfiguration
{
    public const EDITOR = 'editor';
    public const PROJECT_NAME = 'project_name';
    public const ROOT_PATH = 'root_path';
    public const WITH_OUTPUT = 'with_output';
    public const USE_DEVELOP_BRANCH = 'dev';
    public const CREATE_DATABASE = 'create_database';
    public const FORCE_CREATE = 'force_create';
    public const MIGRATE_DATABASE = 'migrate_database';
    public const DATABASE_HOST = 'database_host';
    public const DATABASE_PORT = 'database_port';
    public const DATABASE_NAME = 'database_name';
    public const DATABASE_USERNAME = 'database_username';
    public const DATABASE_PASSWORD = 'database_password';
    public const FRONTEND_FRAMEWORK = 'frontend';
    public const FULL = 'full';
    public const TLD = 'tld';
    public const COMMIT_MESSAGE = 'commit_message';
    public const VALET_LINK = 'valet_link';
    public const VALET_SECURE = 'valet_secure';
    public const BROWSER = 'browser';
    public const TEAMS = 'teams';
    public const INITIALIZE_GITHUB = 'initialize_github';
    public const GITHUB_PUBLIC = 'github_public';
    public const GITHUB_DESCRIPTION = 'github_description';
    public const GITHUB_HOMEPAGE = 'github_homepage';
    public const GITHUB_ORGANIZATION = 'github_organization';
    public const COMMAND = 'command';
    public const BREEZE = 'breeze';
    public const JETSTREAM = 'jetstream';

    public function __construct(array $keyMap)
    {
        $settings = $this->getSettings();

        collect($keyMap)->each(function ($item, $key) use ($settings) {
            $this->$item = $this->get($key, $settings);
        });
    }

    abstract protected function getSettings(): array;

    protected function get(string $key, array $array)
    {
        if (array_key_exists($key, $array)) {
            if ($array[$key] === '') {
                return null;
            }

            if (in_array(Str::lower($array[$key]), ['1', 'true', 'on', 'yes'])) {
                return true;
            }

            if (in_array(Str::lower($array[$key]), ['0', 'false', 'off', 'no'])) {
                return false;
            }

            return $array[$key];
        }

        return null;
    }

    public function __get($name)
    {
        return null;
    }
}


================================================
FILE: app/Configuration/SavedConfiguration.php
================================================
<?php

namespace App\Configuration;

use Dotenv\Dotenv;
use Illuminate\Support\Facades\File;

class SavedConfiguration extends LamboConfiguration
{
    protected function getSettings(): array
    {
        $configurationPath = config('home_dir') . '/' . config('config_dir', '.lambo');
        $configurationFile = config('config_file', 'config');

        if (! File::exists("{$configurationPath}/{$configurationFile}")) {
            return [];
        }

        return Dotenv::createMutable($configurationPath, $configurationFile)->load();
    }
}


================================================
FILE: app/Configuration/SetConfig.php
================================================
<?php

namespace App\Configuration;

use App\Actions\InstallBreeze;
use App\Actions\InstallJetstream;
use App\Commands\Debug;
use App\Commands\NewCommand;
use App\ConsoleWriter;
use App\LamboException;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;

class SetConfig
{
    use Debug;

    protected $consoleWriter;
    protected $fullFlags = [
        LamboConfiguration::CREATE_DATABASE,
        LamboConfiguration::MIGRATE_DATABASE,
        LamboConfiguration::VALET_LINK,
        LamboConfiguration::VALET_SECURE,
    ];
    protected $options;

    private $commandLineConfiguration;
    private $savedConfiguration;
    private $shellConfiguration;
    private $commandLineInput;

    public function __construct(
        CommandLineConfiguration $commandLineConfiguration,
        SavedConfiguration $savedConfiguration,
        ShellConfiguration $shellConfiguration,
        ConsoleWriter $consoleWriter,
        InputInterface $commandLineOptions
    ) {
        $this->commandLineConfiguration = $commandLineConfiguration;
        $this->savedConfiguration = $savedConfiguration;
        $this->shellConfiguration = $shellConfiguration;
        $this->consoleWriter = $consoleWriter;

        $this->commandLineInput = array_filter($commandLineOptions->getOptions(), function ($value, $key) use ($commandLineOptions) {
            return $commandLineOptions->hasParameterOption("--{$key}");
        }, ARRAY_FILTER_USE_BOTH);
    }

    public function __invoke($defaultConfiguration)
    {
        foreach ($defaultConfiguration as $configurationKey => $default) {
            $methodName = 'get' . Str::of($configurationKey)->studly();
            if (method_exists($this, $methodName)) {
                config(["lambo.store.{$configurationKey}" => $this->$methodName($configurationKey, $default)]);
            } else {
                config(["lambo.store.{$configurationKey}" => $this->get($configurationKey, $default)]);
            }
        }

        // If we're in the "new" command, generate a few config items which
        // require others to be set above first.
        if (config('lambo.store.command') === NewCommand::class) {
            $projectPath = config('lambo.store.root_path') . '/' . config('lambo.store.project_name');
            config(['lambo.store.project_path' => $projectPath]);
            config(['lambo.store.project_url' => $this->getProjectURL()]);
        }

        if (config('lambo.store.full')) {
            foreach ($this->fullFlags as $fullFlag) {
                config(["lambo.store.{$fullFlag}" => true]);
            }
        }
    }

    private function get(string $configurationKey, $default)
    {
        if (isset($this->commandLineConfiguration->$configurationKey)) {
            return $this->commandLineConfiguration->$configurationKey;
        }

        if (isset($this->savedConfiguration->$configurationKey)) {
            return $this->savedConfiguration->$configurationKey;
        }

        if (isset($this->shellConfiguration->$configurationKey)) {
            return $this->shellConfiguration->$configurationKey;
        }

        return $default;
    }

    private function getTld(): string
    {
        $valetConfig = config('home_dir') . '/.config/valet/config.json';
        $legacyValetConfig = config('home_dir') . '/.valet/config.json';

        if (File::isFile($valetConfig)) {
            return json_decode(File::get($valetConfig))->tld;
        }

        if (File::isFile($legacyValetConfig)) {
            return json_decode(File::get($legacyValetConfig))->domain;
        }

        throw new LamboException(
            implode(PHP_EOL, [
                'Unable to find valet domain (tld) configuration.',
                'No Valet configuration located at either of the following locations:',
                "- {$valetConfig}",
                "- {$legacyValetConfig}",
            ])
        );
    }

    private function getRootPath(string $key, $default)
    {
        $configuredKeyValue = $this->get($key, $default);

        return ($configuredKeyValue === $default)
            ? $default
            : str_replace('~', config('home_dir'), $configuredKeyValue);
    }

    private function getDatabaseName(string $key, $default)
    {
        return str_replace('-', '_', $this->get($key, $default));
    }

    private function getProjectURL(): string
    {
        return sprintf(
            'http%s://%s.%s',
            config('lambo.store.valet_secure') ? 's' : '',
            config('lambo.store.project_name'),
            config('lambo.store.tld')
        );
    }

    private function getMigrateDatabase(string $key, $default)
    {
        if ($this->commandLineConfiguration->inertia || $this->commandLineConfiguration->livewire) {
            return true;
        }

        return $this->get($key, $default);
    }

    private function getWithOutput(string $key, $default): bool
    {
        if ($this->consoleWriter->getVerbosity() > SymfonyStyle::VERBOSITY_NORMAL) {
            return true;
        }

        return $this->get($key, $default);
    }

    private function getBreeze(string $key, $default)
    {
        $this->ensureOnlyOneStarterKitSelected();

        if (! Arr::has($this->commandLineInput, 'breeze')) {
            return false;
        }

        config(['lambo.store.jetstream' => false]);

        return in_array($this->commandLineInput['breeze'], InstallBreeze::VALID_STACKS)
            ? $this->commandLineInput['breeze']
            : $this->configureBreezeStack();
    }

    private function getJetstream(string $key, $default)
    {
        $this->ensureOnlyOneStarterKitSelected();

        if (! Arr::has($this->commandLineInput, 'jetstream')) {
            return false;
        }

        config(['lambo.store.breeze' => false]);

        return in_array($this->commandLineInput['jetstream'], InstallJetstream::VALID_CONFIGURATIONS)
            ? $this->commandLineInput['jetstream']
            : $this->configureJetstreamStack();
    }

    private function configureBreezeStack(): string
    {
        $this->consoleWriter->note("Laravel Breeze does not provide a <fg=yellow>'{$this->commandLineInput['breeze']}'</> front-end.");
        $choice = $this->consoleWriter->choice('Please choose one of the following', array_keys(InstallBreeze::VALID_STACKS));
        $this->consoleWriter->ok("Using Laravel Breeze with a {$choice} front-end.");

        return Str::lower($choice);
    }

    private function configureJetstreamStack(): string
    {
        $this->consoleWriter->note("<fg=yellow>'{$this->commandLineInput['jetstream']}'</> is not a valid Laravel Jetstream configuration.");
        $stack = $this->consoleWriter->choice('Please choose a front-end', array_keys(InstallJetstream::VALID_STACKS));
        $teams = $this->consoleWriter->confirm('Would you like to use teams?');
        $this->consoleWriter->ok(sprintf('Using %s%s.', $stack, $teams ? ' and teams' : ' without teams'));

        return InstallJetstream::VALID_STACKS[$stack] . ($teams ? ',teams' : '');
    }

    private function ensureOnlyOneStarterKitSelected(): void
    {
        if (Arr::has($this->commandLineInput, ['breeze', 'jetstream'])) {
            $this->consoleWriter->newLine();
            $this->consoleWriter->note('Only one starter-kit may be configured.');

            $choice = $this->consoleWriter->choice('Please choose a starter-kit:', [
                'None',
                'Laravel Breeze',
                'Laravel Jetstream',
            ], 0);

            switch ($choice) {
                case 'Laravel Breeze':
                    unset($this->commandLineConfiguration->jetstream);
                    Arr::forget($this->commandLineInput, 'jetstream');
                    $this->consoleWriter->ok('Using Laravel Breeze');
                    break;
                case 'Laravel Jetstream':
                    Arr::forget($this->commandLineInput, 'breeze');
                    unset($this->commandLineConfiguration->breeze);
                    $this->consoleWriter->ok('Using Laravel Jetstream');
                    break;
                case 'None':
                    Arr::forget($this->commandLineInput, 'jetstream');
                    unset($this->commandLineConfiguration->jetstream);
                    Arr::forget($this->commandLineInput, 'breeze');
                    unset($this->commandLineConfiguration->breeze);
                    $this->consoleWriter->ok('Skipping starter-kit installation.');
                    break;
            }
        }
    }
}


================================================
FILE: app/Configuration/ShellConfiguration.php
================================================
<?php

namespace App\Configuration;

class ShellConfiguration extends LamboConfiguration
{
    protected function getSettings(): array
    {
        return $_SERVER;
    }
}


================================================
FILE: app/ConsoleWriter.php
================================================
<?php

namespace App;

use Illuminate\Console\OutputStyle;
use Symfony\Component\Process\Process;

class ConsoleWriter extends OutputStyle
{
    public const BLUE = 'fg=blue';
    public const GREEN = 'fg=green';
    public const RED = 'fg=red';
    public const MAGENTA = 'fg=magenta';

    public static function formatString(string $string, string $format): string
    {
        return "<{$format}>{$string}</>";
    }

    public function panel(string $prefix, string $message, string $style)
    {
        parent::block($message, $prefix, $style, ' ', true, false);
    }

    public function sectionTitle($sectionTitle)
    {
        $this->newLine();
        $this->text([
            "<fg=yellow;bg=default>{$sectionTitle}</>",
            '<fg=yellow;bg=default>' . str_repeat('#', strlen($sectionTitle)) . '</>',
        ]);
    }

    public function logStep($message)
    {
        parent::block($message, null, 'fg=yellow;bg=default', ' // ', false, false);
    }

    public function exec(string $command)
    {
        $this->labeledLine('EXEC', $command, 'bg=blue;fg=black');
    }

    public function success($message, $label = 'PASS'): void
    {
        $this->labeledLine($label, $message, 'fg=black;bg=green');
    }

    public function ok($message): void
    {
        $this->success($message, ' OK ');
    }

    public function note($message, $label = 'NOTE'): void
    {
        $this->labeledLine($label, $message, 'fg=black;bg=yellow');
    }

    public function warn($message, $label = 'WARN'): void
    {
        $this->labeledLine($label, "<fg=red;bg=default>{$message}</>", 'fg=black;bg=red');
    }

    public function warnCommandFailed($command): void
    {
        $this->warn("Failed to run {$command}");
    }

    public function showOutputErrors(string $errors)
    {
        parent::text([
            '<fg=red;bg=default>--------------------------------------------------------------------------------',
            str_replace(PHP_EOL, PHP_EOL . ' ', trim($errors)),
            '--------------------------------------------------------------------------------</>',
        ]);
    }

    public function showOutput(string $errors)
    {
        parent::text([
            '--------------------------------------------------------------------------------',
            str_replace(PHP_EOL, PHP_EOL . ' ', trim($errors)),
            '--------------------------------------------------------------------------------',
        ]);
    }

    public function exception($message)
    {
        parent::block($message, null, 'fg=black;bg=red', ' ', true, false);
    }

    public function text($message)
    {
        parent::text($message);
    }

    public function listing(array $items): void
    {
        parent::newLine();
        $text = collect($items)->map(function ($dependency) {
            return '  - ' . $dependency;
        })->toArray();
        parent::text($text);
        parent::newLine();
    }

    public function table(array $columnHeadings, array $rowData)
    {
        parent::table($columnHeadings, $rowData);
    }

    public function consoleOutput(string $line, $type)
    {
        if (config('lambo.store.with_output')) {
            ($type === Process::ERR)
                ? $this->labeledLine('!️', '┃ ' . $line, 'fg=yellow')
                : $this->labeledLine('✓︎', '┃ ' . $line, 'fg=green;');
        }
    }

    public function labeledLine(string $label, string $message, string $labelFormat = 'fg=default;bg=default', int $indentColumns = 0): void
    {
        $indent = str_repeat(' ', $indentColumns);
        $this->isDecorated()
            ? parent::text("{$indent}<{$labelFormat}> {$label} </> {$message}")
            : parent::text("{$indent}[ {$label} ] {$message}");
    }
}


================================================
FILE: app/Environment.php
================================================
<?php

namespace App;

class Environment
{
    public static function isMac(): bool
    {
        return PHP_OS === 'Darwin';
    }
}


================================================
FILE: app/Helpers/GetTimezone.php
================================================
<?php

namespace App\Helpers;

use IntlTimeZone;

class GetTimezone
{
    public function __invoke(): string
    {
        if ($timezone = ini_get('date.timezone')) {
            return $timezone;
        }

        return IntlTimeZone::createDefault()->getID();
    }
}


================================================
FILE: app/LamboException.php
================================================
<?php

namespace App;

use Exception;

class LamboException extends Exception
{
}


================================================
FILE: app/LogsToConsole.php
================================================
<?php

namespace App;

trait LogsToConsole
{
    public function alert(string $message)
    {
        app('console')->alert($message);
    }

    public function warn(string $message)
    {
        app('console')->warn($message);
    }

    public function error(string $message)
    {
        app('console')->error($message);
    }

    public function line(string $message)
    {
        app('console')->line($message);
    }

    public function info(string $message)
    {
        app('console')->info($message);
    }
}


================================================
FILE: app/Options.php
================================================
<?php

namespace App;

class Options
{
    protected $options = [
        /** Parameters first, then flags */
        [
            'short' => 'e',
            'long' => 'editor',
            'param_description' => 'EDITOR',
            'cli_description' => "Specify an editor to run <info>'EDITOR .'</info> with after",
        ],
        [
            'short' => 'p',
            'long' => 'path',
            'param_description' => 'PATH',
            'cli_description' => 'Customize the path in which the new project will be created',
        ],
        [
            'short' => 'm',
            'long' => 'message',
            'param_description' => 'MESSAGE',
            'cli_description' => 'Customize the initial commit message (wrap with quotes!)',
        ],
        [
            'short' => 'g',
            'long' => 'github',
            'cli_description' => 'Initialize a new private GitHub repository',
        ],
        [
            'long' => 'gh-public',
            'cli_description' => 'Make the new GitHub repository public',
        ],
        [
            'long' => 'gh-description',
            'param_description' => 'DESCRIPTION',
            'cli_description' => 'Initialize the new GitHub repository with the provided <info>DESCRIPTION</info>',
        ],
        [
            'long' => 'gh-homepage',
            'param_description' => 'URL',
            'cli_description' => 'Initialize the new GitHub repository with the provided homepage <info>URL</info>',
        ],
        [
            'long' => 'gh-org',
            'param_description' => 'ORG',
            'cli_description' => 'Initialize the new GitHub repository for <info>ORG</info>/project',
        ],
        [
            'long' => 'breeze',
            'param_description' => 'STACK',
            'cli_description' => 'Use the Laravel Breeze starter kit. <info>STACK</info> may be either <info>blade</info>, <info>vue</info> or <info>react</info>.',
        ],
        [
            'long' => 'jetstream',
            'param_description' => 'STACK[,teams]',
            'cli_description' => 'Use the Laravel Jetstream starter kit. <info>STACK</info> may be either <info>inertia</info> or <info>livewire</info>.' ,
        ],
        [
            'short' => 'b',
            'long' => 'browser',
            'param_description' => 'BROWSER',
            'cli_description' => 'Open the site in the specified <info>BROWSER</info>. E.g. <info>firefox</info>',
        ],
        [
            'long' => 'dbhost',
            'param_description' => 'HOST',
            'cli_description' => 'Specify the database <info>HOST</info>',
        ],
        [
            'long' => 'dbport',
            'param_description' => 'PORT',
            'cli_description' => 'Specify the database <info>PORT</info>',
        ],
        [
            'long' => 'dbname',
            'param_description' => 'NAME',
            'cli_description' => 'Specify the database <info>NAME</info>',
        ],
        [
            'long' => 'dbuser',
            'param_description' => 'USERNAME',
            'cli_description' => 'Specify the database <info>USERNAME</info>',
        ],
        [
            'long' => 'dbpassword',
            'param_description' => 'PASSWORD',
            'cli_description' => 'Specify the database <info>PASSWORD</info>',
        ],
        [
            'long' => 'create-db',
            'cli_description' => 'Create a new MySQL database',
        ],
        [
            'short' => 'f',
            'long' => 'force',
            'cli_description' => 'Force install even if the directory already exists',
        ],
        [
            'long' => 'migrate-db',
            'cli_description' => 'Run database migrations',
        ],
        [
            'short' => 'l',
            'long' => 'link',
            'cli_description' => 'Create a Valet link to the project directory',
        ],
        [
            'short' => 's',
            'long' => 'secure',
            'cli_description' => 'Generate and use an HTTPS cert with Valet',
        ],
        [
            'short' => 'd',
            'long' => 'dev',
            'cli_description' => 'Install Laravel using the develop branch',
        ],
        [
            'long' => 'full',
            'cli_description' => 'Shortcut of --create-db --migrate-db --link --secure',
        ],
        [
            'short' => 'q',
            'long' => 'quiet',
            'cli_description' => 'Do not output to the console (except for user input)',
        ],
    ];

    public function all(): array
    {
        return $this->options;
    }
}


================================================
FILE: app/Providers/AppServiceProvider.php
================================================
<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        if (function_exists('posix_getuid')) {
            // Mac or Linux
            $path = posix_getpwuid(posix_getuid())['dir'];
        } else {
            // Windows
            $path = exec('echo %USERPROFILE%');
        }

        config()->set([
            'home_dir' => $path,
        ]);
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}


================================================
FILE: app/Shell.php
================================================
<?php

namespace App;

use Illuminate\Contracts\Config\Repository;
use Symfony\Component\Process\Process;

class Shell
{
    protected $rootPath;
    protected $projectPath;
    protected $consoleWriter;

    private $useTTY = false;

    public function __construct(Repository $config, ConsoleWriter $consoleWriter)
    {
        $this->rootPath = $config->get('lambo.store.root_path');
        $this->projectPath = $config->get('lambo.store.project_path');
        $this->consoleWriter = $consoleWriter;
    }

    public function execInRoot($command)
    {
        return $this->exec("cd {$this->rootPath} && $command");
    }

    public function execInProject($command)
    {
        return $this->exec("cd {$this->projectPath} && $command");
    }

    public function execIn(string $directory, string $command)
    {
        return $this->exec("cd {$directory} && $command");
    }

    public function exec(string $command)
    {
        $this->consoleWriter->exec($command);

        $process = Process::fromShellCommandline($command)
            ->setTty($this->useTTY)
            ->setTimeout(null)
            ->enableOutput();
        $process->run(function ($type, $buffer) {
            if (empty(trim($buffer)) || $buffer === PHP_EOL) {
                return;
            }

            foreach (explode(PHP_EOL, trim($buffer)) as $line) {
                $this->consoleWriter->consoleOutput($line, $type);
            }
        });
        $this->useTTY = false;

        return $process;
    }

    public function execQuietly(string $command)
    {
        $process = Process::fromShellCommandline($command)
            ->setTimeout(null)
            ->enableOutput();

        $process->run();

        return $process;
    }

    public function withTTY()
    {
        $this->useTTY = true;
        return $this;
    }
}


================================================
FILE: app/Tools/Database.php
================================================
<?php

namespace App\Tools;

use PDO;

class Database
{
    private $dsn;
    private $username;
    private $password;

    public function fill(string $type, string $host, $port, string $username, $password): self
    {
        $this->dsn = "{$type}:host={$host};port={$port}";
        $this->username = $username;
        $this->password = $password;

        return $this;
    }

    public function fillFromUrl(string $url): self
    {
        $url = parse_url($url);

        return $this->fill($url['scheme'], $url['host'], $url['port'], $url['user'], $url['pass']);
    }

    public function fillFromLamboStore(array $store): self
    {
        return $this->fill(
            $type = 'mysql',
            $host = $store['database_host'],
            $port = $store['database_port'],
            $username = $store['database_username'],
            $password = $store['database_password']
        );
    }

    public function ensureExists(string $databaseName = null)
    {
        $dsn = is_null($databaseName)
            ? $this->dsn
            : "{$this->dsn};dbname={$databaseName}";

        new PDO($dsn, $this->username, $this->password);
    }

    public function create(string $databaseName)
    {
        $connection = new PDO($this->dsn, $this->username, $this->password);
        return $connection->exec("CREATE DATABASE IF NOT EXISTS {$databaseName};") === 1;
    }
}


================================================
FILE: bin/testLambo.sh
================================================
#!/usr/bin/env bash

# ------------------------------------------------------------------------------
# THIS SCRIPT WILL ONLY WORK ON *NIX SYSTEMS. SORRY WINDOWS USERS.
#
# Manual testing script that speeds things up by copying a "template"
# installation of Laravel rather than running the Laravel Installer every time.
# Useful when running lambo over and over during testing.
#
# NOTE: on first run since boot the script will install a fresh version of the
# Laravel template.
#
# 1. Comment out the following in app/Commands/NewCommand:
#    app(VerifyPathAvailable::class)()
#    app(InstallLaravel::class)()
#
# 2. run this script passing any regular lambo flags and/or options while
#    omitting new, Example:
#
#   /path/to/testLambo.sh my-project [other lambo flags]
# ------------------------------------------------------------------------------

DEBUG=false

if [ "$#" -lt "1" ]; then
  echo "usage: $0 name [regular lambo parameters]"
  exit
fi

START_DIR=$(pwd)
cd $(dirname $0)
SCRIPT_PATH=$(pwd)

NAME=$1
shift

TEST_DIR="/tmp/lambo"
TEMPLATE_NAME="template"
PROJECT_PATH="$TEST_DIR/$NAME"
TEMPLATE_PATH="$TEST_DIR/$TEMPLATE_NAME"

if [ "$DEBUG" = true ]; then
  echo " [INFO] Start directory: $START_DIR"
  echo " [INFO] Script path: $SCRIPT_PATH"
  echo " [INFO] Test directory: $TEST_DIR"
  echo " [INFO] Project name: $NAME"
  echo " [INFO] Project path: $PROJECT_PATH"
  echo " [INFO] Template name: $TEMPLATE_NAME"
  echo " [INFO] Template path: $TEMPLATE_PATH"
fi

# Create test directory
if [ ! -d "$TEST_DIR" ]; then
  echo "*[WARN] Test directory '$TEST_DIR' does not exist, creating it now…"
  mkdir $TEST_DIR
else
  echo " [INFO] Using test directory '$TEST_DIR'"
fi

# Create template Laravel installation
if [ ! -d "$TEMPLATE_PATH" ]; then
  echo "*[WARN] Laravel template '$TEMPLATE_PATH' does not exist, creating it now…"
  cd $TEST_DIR
  composer create-project laravel/laravel $TEMPLATE_NAME --remove-vcs --prefer-dist --quiet
  cd $START_DIR
  echo " [INFO] Created template '$TEMPLATE_PATH'"
else
  echo " [INFO] Using template '$TEMPLATE_PATH'"
fi

# remove previous run.
if [ -f "$TEST_DIR/.last-run" ]; then
  last_run=$(cat $TEST_DIR/.last-run)
  rm -rf $last_run
  echo " [INFO] Deleted previous run '$last_run'"
fi

cp -r $TEMPLATE_PATH $PROJECT_PATH
echo " [INFO] Copied laravel template '$TEMPLATE_PATH' to '$PROJECT_PATH'"

cd $TEST_DIR
echo $PROJECT_PATH > .last-run

cd $SCRIPT_PATH
echo " [INFO] Running Lambo…"
echo
echo "lambo new $NAME --path $TEST_DIR $*"
../lambo new $NAME --path $TEST_DIR $*


================================================
FILE: bootstrap/app.php
================================================
<?php

/*
|--------------------------------------------------------------------------
| Create The Application
|--------------------------------------------------------------------------
|
| The first thing we will do is create a new Laravel application instance
| which serves as the "glue" for all the components of Laravel, and is
| the IoC container for the system binding all of the various parts.
|
*/

$app = new LaravelZero\Framework\Application(
    dirname(__DIR__)
);

/*
|--------------------------------------------------------------------------
| Bind Important Interfaces
|--------------------------------------------------------------------------
|
| Next, we need to bind some important interfaces into the container so
| we will be able to resolve them when needed. The kernels serve the
| incoming requests to this application from both the web and CLI.
|
*/

$app->singleton(
    Illuminate\Contracts\Console\Kernel::class,
    LaravelZero\Framework\Kernel::class
);

$app->singleton(
    Illuminate\Contracts\Debug\ExceptionHandler::class,
    Illuminate\Foundation\Exceptions\Handler::class
);

/*
|--------------------------------------------------------------------------
| Return The Application
|--------------------------------------------------------------------------
|
| This script returns the application instance. The instance is given to
| the calling script so we can separate the building of the instances
| from the actual running of the application and sending responses.
|
*/

return $app;


================================================
FILE: box.json
================================================
{
    "chmod": "0755",
    "directories": [
        "app",
        "bootstrap",
        "config",
        "stubs",
        "vendor"
    ],
    "files": [
        "composer.json"
    ],
    "exclude-dev-files": false,
    "exclude-composer-files": false,
    "compression": "GZ",
    "compactors": [
        "KevinGH\\Box\\Compactor\\Php",
        "KevinGH\\Box\\Compactor\\Json"
    ]
}


================================================
FILE: composer.json
================================================
{
    "name": "tightenco/lambo",
    "description": "Super-powered 'laravel new' with Laravel and Valet.",
    "keywords": [
        "laravel",
        "zonda",
        "wwdhhd",
        "lambo"
    ],
    "type": "project",
    "license": "MIT",
    "authors": [
        {
            "name": "Matt Stauffer",
            "email": "matt@tighten.co"
        },
        {
            "name": "Jon Sugar"
        }
    ],
    "require": {
        "php": "^8.0",
        "ext-json": "*",
        "ext-pdo": "*",
        "ext-intl": "*"
    },
    "require-dev": {
        "laravel-zero/framework": "^10.0",
        "mockery/mockery": "^1.0",
        "pestphp/pest": "^2.5",
        "spatie/laravel-ray": "^1.17",
        "tightenco/duster": "^1.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "config": {
        "preferred-install": "dist",
        "sort-packages": true,
        "optimize-autoloader": true,
        "allow-plugins": {
            "dealerdirect/phpcodesniffer-composer-installer": true,
            "pestphp/pest-plugin": true
        }
    },
    "minimum-stability": "dev",
    "prefer-stable": true,
    "bin": ["builds/lambo"]
}


================================================
FILE: config/app.php
================================================
<?php

use App\Helpers\GetTimezone;

return [

    /*
    |--------------------------------------------------------------------------
    | Application Name
    |--------------------------------------------------------------------------
    |
    | This value is the name of your application. This value is used when the
    | framework needs to place the application's name in a notification or
    | any other location as required by the application or its packages.
    |
    */

    'name' => 'Lambo',

    /*
    |--------------------------------------------------------------------------
    | Application Version
    |--------------------------------------------------------------------------
    |
    | This value determines the "version" your application is currently running
    | in. You may want to follow the "Semantic Versioning" - Given a version
    | number MAJOR.MINOR.PATCH when an update happens: https://semver.org.
    |
    */

    'version' => app('git.version'),

    /*
    |--------------------------------------------------------------------------
    | Application Environment
    |--------------------------------------------------------------------------
    |
    | This value determines the "environment" your application is currently
    | running in. This may determine how you prefer to configure various
    | services your application utilizes. Should be true in production.
    |
    */

    'env' => 'development',

    /*
    |--------------------------------------------------------------------------
    | Timezone
    |--------------------------------------------------------------------------
    |
    | This value determines the timezone that Lambo is currently running in.
    | It will be the value of "date.timezone" in php.ini or the value set
    | by your operating system. If php cannot determine the value set
    | by your operating system, then UTC will be used. You may set
    | this value manually to use a timezone of your choosing.
    */
    'timezone' => app(GetTimezone::class)(),

    /*
    |--------------------------------------------------------------------------
    | Autoloaded Service Providers
    |--------------------------------------------------------------------------
    |
    | The service providers listed here will be automatically loaded on the
    | request to your application. Feel free to add your own services to
    | this array to grant expanded functionality to your applications.
    |
    */

    'providers' => [
        App\Providers\AppServiceProvider::class,
    ],

];


================================================
FILE: config/commands.php
================================================
<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Default Command
    |--------------------------------------------------------------------------
    |
    | Laravel Zero will always run the command specified below when no command name is
    | provided. Consider update the default command for single command applications.
    | You cannot pass arguments to the default command because they are ignored.
    |
    */

    'default' => App\Commands\HelpCommand::class,

    /*
    |--------------------------------------------------------------------------
    | Commands Paths
    |--------------------------------------------------------------------------
    |
    | This value determines the "paths" that should be loaded by the console's
    | kernel. Foreach "path" present on the array provided below the kernel
    | will extract all "Illuminate\Console\Command" based class commands.
    |
    */

    'paths' => [app_path('Commands')],

    /*
    |--------------------------------------------------------------------------
    | Added Commands
    |--------------------------------------------------------------------------
    |
    | You may want to include a single command class without having to load an
    | entire folder. Here you can specify which commands should be added to
    | your list of commands. The console's kernel will try to load them.
    |
    */

    'add' => [
        // ..
    ],

    /*
    |--------------------------------------------------------------------------
    | Hidden Commands
    |--------------------------------------------------------------------------
    |
    | Your application commands will always be visible on the application list
    | of commands. But you can still make them "hidden" specifying an array
    | of commands below. All "hidden" commands can still be run/executed.
    |
    */

    'hidden' => [
        NunoMaduro\LaravelConsoleSummary\SummaryCommand::class,
        Symfony\Component\Console\Command\HelpCommand::class,
        Illuminate\Console\Scheduling\ScheduleRunCommand::class,
        Illuminate\Console\Scheduling\ScheduleFinishCommand::class,
        Illuminate\Foundation\Console\VendorPublishCommand::class,
    ],

    /*
    |--------------------------------------------------------------------------
    | Removed Commands
    |--------------------------------------------------------------------------
    |
    | Do you have a service provider that loads a list of commands that
    | you don't need? No problem. Laravel Zero allows you to specify
    | below a list of commands that you don't to see in your app.
    |
    */

    'remove' => [
        Symfony\Component\Console\Command\HelpCommand::class,
    ],

];


================================================
FILE: lambo
================================================
#!/usr/bin/env php
<?php

define('LARAVEL_START', microtime(true));

/*
|--------------------------------------------------------------------------
| Register The Auto Loader
|--------------------------------------------------------------------------
|
| Composer provides a convenient, automatically generated class loader
| for our application. We just need to utilize it! We'll require it
| into the script here so that we do not have to worry about the
| loading of any our classes "manually". Feels great to relax.
|
*/

$autoloader = require file_exists(__DIR__ . '/vendor/autoload.php') ? __DIR__ . '/vendor/autoload.php' : __DIR__ . '/../../autoload.php';

$app = require_once __DIR__ . '/bootstrap/app.php';

/*
|--------------------------------------------------------------------------
| Run The Artisan Application
|--------------------------------------------------------------------------
|
| When we run the console application, the current CLI command will be
| executed in this console and the response sent back to a terminal
| or another output device for the developers. Here goes nothing!
|
*/

$kernel = $app->make(Illuminate\Contracts\Console\Kernel::class);

$app->bind('Symfony\Component\Console\Output\ConsoleOutput', function () {
    return new Symfony\Component\Console\Output\ConsoleOutput;
});


$status = $kernel->handle(
    $input = new Symfony\Component\Console\Input\ArgvInput,
    $app->make('Symfony\Component\Console\Output\ConsoleOutput')
);

/*
|--------------------------------------------------------------------------
| Shutdown The Application
|--------------------------------------------------------------------------
|
| Once Artisan has finished running, we will fire off the shutdown events
| so that any final work may be done by the application before we shut
| down the process. This is the last thing to happen to the request.
|
*/

$kernel->terminate($input, $status);

exit($status);


================================================
FILE: phpunit.xml.dist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
>
    <testsuites>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
    </testsuites>
    <source>
        <include>
            <directory suffix=".php">./app</directory>
        </include>
    </source>
</phpunit>

================================================
FILE: readme.md
================================================
![Lambo logo](https://raw.githubusercontent.com/tighten/lambo/main/lambo-banner.png)

[![Run tests](https://github.com/tighten/takeout/workflows/Run%20tests/badge.svg?branch=main)](https://github.com/tighten/lambo/actions?query=workflow%3A%22Run+Tests%22)

**Super-powered `laravel new` for Laravel and Valet**

Lambo is a command-line tool that replaces the Laravel installer and wraps up the most common tasks you might take when creating a Laravel app: opening it in your editor and your browser, initialize a git repository, tweak your `.env` and `.env.example`, and more.


# Requirements

- PHP 7.3+
- (optional, but beneficial) [Laravel Valet](https://laravel.com/docs/valet)

# Installation

```bash
composer global require tightenco/lambo:^3.0
```

# Upgrading

```bash
composer global update tightenco/lambo
```

# Usage

Make sure `~/.composer/vendor/bin` is in your terminal's path.

```bash
cd ~/Sites
lambo new myNextProject
```

# What exactly does it do?

- `laravel new $PROJECTNAME`
- Initialize a git repo, add all the files, and, after some changes below, make a commit with the text "Initial commit."
- Replace the `.env` (and `.env.example`) database credentials with the default macOS MySQL credentials: database of `$PROJECTNAME`, user `root`, and empty password
- Replace the `.env` (and `.env.example`) `APP_URL` with `$PROJECTNAME.$YOURVALETTLD`
- Generate an app key
- Open the project in your favorite editor
- Open `$PROJECTNAME.$YOURVALETTLD` in your browser

> Note: If your `$PROJECTNAME` has dashes (`-`) in it, they will be replaced with underscores (`_`) in the database name.

There are also a few optional behaviors based on the parameters you pass (or define in your config file), including creating a database, migrating, installing Jetstream, running Valet Link and/or Secure, and running a custom bash script of your definition after the fact.

# Customizing Lambo

While the default actions Lambo provides are great, most users will want to customize at least a few of the steps. Thankfully, Lambo is built to be customized!

There are three ways to customize your usage of Lambo: command-line arguments, a config file, and an "after" file.

Most users will want to set their preferred configuration options once and then never think about it again. That's best solved by creating a config file.

But if you find yourself needing to change the way you interact with Lambo on a project-by-project basis, you may also want to use the command-line parameters to customize Lambo when you're using it.

## Creating a config file

You can create a config file at `~/.lambo/config` rather than pass the same arguments each time you create a new project.

The following command creates the file, if it doesn't exist, and edits it:

```bash
lambo edit-config
```

The config file contains the configuration parameters you can customize, and will be read on every usage of Lambo.

## Creating an "after" file

You can also create an after file at `~/.lambo/after` to run additional commands after you create a new project.

The following command creates the file, if it doesn't exist, and edits it:

```bash
lambo edit-after
```

The after file is interpreted as a bash script, so you can include any commands here, such as installing additional composer dependencies...

```bash
# Install additional composer dependencies as you would from the command line.
echo "Installing Composer Dependencies"
composer require tightenco/mailthief tightenco/quicksand
```

...or copying additional files to your new project.

```bash
# To copy standard files to new lambo project place them in ~/.lambo/includes directory.
echo "Copying Include Files"
cp -R ~/.lambo/includes/ $PROJECTPATH
```

You also have access to variables from your config file such as `$PROJECTPATH` and `$CODEEDITOR`.

## Using command-line parameters

Any command-line parameters passed in will override Lambo's defaults and your config settings. See a [full list of the parameters you can pass in](#parameters).

# Lambo Commands

- `help` or `help-screen` show the help screen

<a id="config-files"></a>
- `edit-config` edits your config file (and creates one if it doesn't exist)

  ```bash
  lambo edit-config
  ```

- `edit-after` edits your "after" file (and creates one if it doesn't exist)

  ```bash
  lambo edit-after
  ```


<a id="parameters"></a>
# Configurable parameters

You can optionally pass one or more of these parameters every time you use Lambo. If you find yourself wanting to configure any of these settings every time you run Lambo, that's a perfect use for the [config files](#config-files).

- `-e` or `--editor` to define your editor command. Whatever is passed here will be run as `$EDITOR .` after creating the project.

  ```bash
  # runs "subl ." in the project directory after creating the project
  lambo new superApplication --editor=subl
  ```

- `-p` or `--path` to specify where to install the application.

  ```bash
  lambo new superApplication --path=~/Sites
  ```

- `-m` or `--message` to set the first Git commit message.

  ```bash
  lambo new superApplication --message="This lambo runs fast!"
  ```

- `-f` or `--force` to force install even if the directory already exists 

  ```bash
  # Creates a new Laravel application after deleting ~/Sites/superApplication  
  lambo new superApplication --force
  ```
  
- `-d` or `--dev` to choose the `develop` branch instead of `master`, getting the beta install.

  ```bash
  lambo new superApplication --dev
  ```

- `-b` or `--browser` to define which browser you want to open the project in.

  ```bash
  lambo new superApplication --browser="/Applications/Google Chrome Canary.app"
  ```

- `-l` or `--link` to create a Valet link to the project directory.

  ```bash
  lambo new superApplication --link
  ```

- `-s` or `--secure` to secure the Valet site using https.

  ```bash
  lambo new superApplication --secure
  ```

- `--create-db` to create a new MySQL database which has the same name as your project.
  This requires `mysql` command to be available on your system.

  ```bash
  lambo new superApplication --create-db
  ```

- `--migrate-db` to migrate your database.

  ```bash
  lambo new superApplication --migrate-db
  ```

- `--dbuser` to specify the database username.

  ```bash
  lambo new superApplication --dbuser=USER
  ```

- `--dbpassword` specify the database password.

  ```bash
  lambo new superApplication --dbpassword=SECRET
  ```

- `--dbhost` specify the database host.

  ```bash
  lambo new superApplication --dbhost=127.0.0.1
  ```

- `--breeze=STACK` to use the Laravel Breeze starter kit. `STACK` may be either `blade`, `vue` or `react`.

  ```bash
  lambo new superApplication --breeze=blade
  lambo new superApplication --breeze=vue
  lambo new superApplication --breeze=react
  ```

- `--jetstream=STACK[,teams]` to use the Laravel Jetstream starter kit. `STACK` may be either `inertia` or `livewire`.

  ```bash
  lambo new superApplication --jetstream=inertia
  lambo new superApplication --jetstream=inertia,teams
  lambo new superApplication --jetstream=livewire
  lambo new superApplication --jetstream=livewire,teams
  ```
  
- `--full` to use `--create-db`, `--migrate-db`, `--link`, and `-secure`.

  ```bash
  lambo new superApplication --full

**GitHub Repository Creation**

**Important:** To create new repositories Lambo requires one of the following tools to be installed:
- the official [GitHub command line tool](https://github.com/cli/cli#installation)
- the [hub command line tool](https://github.com/github/hub#installation)
 
Lambo will give you the option to continue without GitHub repository creation if neither tool is installed.

- `-g` or `--github` to  Initialize a new private GitHub repository and push your new project to it.

```bash
# Repository created at https://github.com/<your_github_username>/superApplication
lambo new superApplication --github
```

- Use `--gh-public` with `--github` to make the new GitHub repository public.

```bash
lambo new superApplication --github --gh-public
```

- Use `--gh-description` with `--github` to initialize the new GitHub repository with a description.

```bash
lambo new superApplication --github --gh-description='My super application'
```
- Use `--gh-homepage` with `--github` to initialize the new GitHub repository with a homepage url. 

```bash
lambo new superApplication --github --gh-homepage=https://example.com
```
- Use `--gh-org` with `--github` to initialize the new GitHub repository with a specified organization.

```bash
# Repository created at https://github.com/acme/superApplication
lambo new superApplication --github --gh-org=acme
```

-----

# For contributors:

## Process for release

If you're working with us and are assigned to push a release, here's the easiest process:

1. Visit the [Lambo Releases page](https://github.com/tighten/lambo/releases); figure out what your next tag will be (increase the third number if it's a patch or fix; increase the second number if it's adding features)
2. On your local machine, pull down the latest version of `main` (`git checkout main && git pull`)
3. Build for the version you're targeting (`./lambo app:build`)
4. Run the build once to make sure it works (`./builds/lambo`)
5. Commit your build and push it up
6. [Draft a new release](https://github.com/tighten/lambo/releases/new) with both the tag version and release title of your tag (e.g. `v1.5.1`)
7. Set the body to be a bullet-point list with simple descriptions for each of the PRs merged, as well as the PR link in parentheses at the end. For example:

    `- Add a superpower (#92)`
8. Hit `Publish release`
9. Profit

## Notes for future development

- All new configuration keys must be added to the `$newConfiguration` property in `UpgradeSavedConfiguration`
- All removed or deprecated configuration keys must be added to the `$removedConfigurationKeys` property in `UpgradeSavedConfiguration`
- Any time configuration keys are changed, the `$configurationVersion` property in `UpgradeSavedConfiguration` needs to be incremented


================================================
FILE: stubs/after
================================================
#!/usr/bin/env bash

# Install additional composer dependencies as you would from the command line.
# echo "
# Installing Composer Dependencies
# "
# composer require tightenco/mailthief tightenco/quicksand

# To copy standard files to new lambo project place them in ~/.lambo/includes directory.
# echo "
# Copying Include Files
# "
# cp -R ~/.lambo/includes/ $PROJECTPATH

# To add a git commit after given modifications
# echo "
# Committing after modifications to Git
# "
# git add .
# git commit -am "Initialize Composer dependencies and additional files."


================================================
FILE: stubs/config
================================================
PROJECTPATH=
MESSAGE="Initial commit."
DEVELOP=false
CODEEDITOR=
BROWSER=
LINK=false
SECURE=false
CREATE_DATABASE=false
MIGRATE_DATABASE=false
DB_HOST=127.0.0.1
DB_PORT=
DB_NAME=
DB_USERNAME=root
DB_PASSWORD=



================================================
FILE: tests/CreatesApplication.php
================================================
<?php

namespace Tests;

use Illuminate\Contracts\Console\Kernel;

trait CreatesApplication
{
    /**
     * Creates the application.
     *
     * @return \Illuminate\Foundation\Application
     */
    public function createApplication()
    {
        $app = require __DIR__ . '/../bootstrap/app.php';

        $app->make(Kernel::class)->bootstrap();

        return $app;
    }
}


================================================
FILE: tests/Feature/CreateDatabaseTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\CreateDatabase;
use App\Tools\Database;
use Tests\TestCase;

class CreateDatabaseTest extends TestCase
{
    private $database;

    public function setUp(): void
    {
        parent::setUp();

        $this->database = $this->mock(Database::class);
    }

    /** @test */
    function it_creates_a_mysql_database()
    {
        $fakeStore = [
            'create_database' => true,
            'database_host' => 'example.test',
            'database_port' => 3306,
            'database_username' => 'user',
            'database_password' => 'password',
            'database_name' => 'foo',
        ];

        $this->database->shouldReceive('fillFromLamboStore')
            ->with($fakeStore)
            ->once()
            ->andReturnSelf();

        $this->database->shouldReceive('create')
            ->once()
            ->globally()
            ->andReturnTrue()
            ->ordered();

        config(['lambo.store' => $fakeStore]);

        app(CreateDatabase::class)();
    }

    /** @test */
    function it_skips_database_creation()
    {
        $spy = $this->spy(Database::class);

        config(['lambo.store.create_database' => false]);

        config(['lambo.store.database_host' => 'example.test']);
        config(['lambo.store.database_port' => 3306]);
        config(['lambo.store.database_username' => 'user']);
        config(['lambo.store.database_password' => 'password']);
        config(['lambo.store.database_name' => 'foo']);

        app(CreateDatabase::class)();

        $spy->shouldNotHaveReceived('find');
        $spy->shouldNotHaveReceived('createSchema');
    }
}


================================================
FILE: tests/Feature/CustomizeDotEnvTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\CustomizeDotEnv;
use Illuminate\Support\Facades\File;
use Tests\TestCase;

class CustomizeDotEnvTest extends TestCase
{
    /** @test */
    function it_saves_the_customized_dot_env_files()
    {
        config(['lambo.store.project_name' => 'my-project']);
        config(['lambo.store.database_name' => 'my_project']);
        config(['lambo.store.project_url' => 'http://my-project.example.com']);
        config(['lambo.store.database_username' => 'username']);
        config(['lambo.store.database_password' => 'password']);
        config(['lambo.store.project_path' => '/some/project/path']);

        $originalDotEnv = File::get(base_path('tests/Feature/Fixtures/.env.original'));
        $customizedDotEnv = File::get(base_path('tests/Feature/Fixtures/.env.customized'));

        File::shouldReceive('get')
            ->once()->with('/some/project/path/.env.example')
            ->andReturn($originalDotEnv);

        File::shouldReceive('put')
            ->with('/some/project/path/.env.example', $customizedDotEnv);

        File::shouldReceive('put')
            ->with('/some/project/path/.env', $customizedDotEnv);

        app(CustomizeDotEnv::class)();
    }

    /** @test */
    function it_replaces_static_strings()
    {
        config()->set('lambo.store.database_username', 'root');

        $customizeDotEnv = app(CustomizeDotEnv::class);
        $contents = 'DB_USERNAME=previous';
        $contents = $customizeDotEnv->customize($contents);
        $this->assertEquals('DB_USERNAME=root', $contents);
    }

    /** @test */
    function un_targeted_lines_are_unchanged()
    {
        config()->set('lambo.store.database_username', 'root');

        $customizeDotEnv = app(CustomizeDotEnv::class);
        $contents = "DB_USERNAME=previous\nDONT_TOUCH_ME=cant_touch_me";
        $contents = $customizeDotEnv->customize($contents);
        $this->assertEquals("DB_USERNAME=root\nDONT_TOUCH_ME=cant_touch_me", $contents);
    }

    /** @test */
    function lines_with_no_equals_are_unchanged()
    {
        $customizeDotEnv = app(CustomizeDotEnv::class);
        $contents = "SOME_VALUE=previous\nABCDEFGNOEQUALS";
        $contents = $customizeDotEnv->customize($contents);
        $this->assertEquals("SOME_VALUE=previous\nABCDEFGNOEQUALS", $contents);
    }

    /** @test */
    function line_breaks_remain()
    {
        $customizeDotEnv = app(CustomizeDotEnv::class);
        $contents = "A=B\n\nC=D";
        $contents = $customizeDotEnv->customize($contents);
        $this->assertEquals("A=B\n\nC=D", $contents);
    }
}


================================================
FILE: tests/Feature/EditConfigFileTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\EditConfigFile;
use App\LamboException;
use Illuminate\Support\Facades\File;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class EditConfigFileTest extends TestCase
{
    private $fileName;
    private $configDirectory;
    private $configFilePath;
    private $fileTemplate;
    public function setUp(): void
    {
        parent::setUp();

        $this->fileName = 'my-config-file-name';
        $homeDirectory = '/my/home/directory';
        $this->configDirectory = "{$homeDirectory}/.lambo";
        $this->configFilePath = "{$this->configDirectory}/{$this->fileName}";

        config(['home_dir' => $homeDirectory]);
        config(['lambo.store.editor' => 'vim']);

        $this->fileTemplate = 'my-config-file-template';
    }

    /** @test */
    function it_creates_the_config_directory_and_file_then_opens_the_file_for_editing()
    {
        $when = $and = $then = $this;

        $when->the_config_directory_does_not_exist();
        $and->the_config_directory_is_created();

        $and->the_config_file_does_not_exist();
        $and->the_config_file_is_created();

        $then->the_config_file_is_opened_for_editing();

        app(EditConfigFile::class)($this->fileName);
    }

    /** @test */
    function it_creates_a_config_file_then_opens_the_file_for_editing()
    {
        $this->configDirectoryExists();
        $this->configFileExists(false);
        $this->successfullyCreateConfigFile();
        $this->successfullyOpenInEditor();

        app(EditConfigFile::class)($this->fileName);
    }

    /** @test */
    function it_opens_a_config_file_for_editing()
    {
        $this->configDirectoryExists();
        $this->configFileExists();
        $this->successfullyOpenInEditor();

        app(EditConfigFile::class)($this->fileName);
    }

    /** @test */
    function it_throws_an_exception_if_the_configured_editor_fails_to_open()
    {
        $this->configDirectoryExists();
        $this->configFileExists();
        $this->successfullyOpenInEditor(false);

        $this->expectException(LamboException::class);

        app(EditConfigFile::class)($this->fileName);
    }

    /** @test */
    function failing_to_create_the_configuration_directory_throws_an_exception()
    {
        $this->configDirectoryExists(false);
        $this->successfullyCreateConfigDirectory(false);

        $this->expectException(LamboException::class);

        app(EditConfigFile::class)($this->fileName);
    }

    /** @test */
    public function failing_to_create_the_configuration_file_throws_an_exception()
    {
        $this->configDirectoryExists();
        $this->configFileExists(false);
        $this->successfullyCreateConfigFile(false);

        $this->expectException(LamboException::class);

        app(EditConfigFile::class)($this->fileName);
    }

    private function configDirectoryExists(bool $exists = true): void
    {
        File::shouldReceive('isDirectory')
            ->with($this->configDirectory)
            ->once()
            ->andReturn($exists)
            ->globally()
            ->ordered();
    }

    private function successfullyCreateConfigDirectory(bool $success = true): void
    {
        File::shouldReceive('makeDirectory')
            ->with($this->configDirectory)
            ->once()
            ->andReturn($success)
            ->globally()
            ->ordered();
    }

    private function configFileExists(bool $success = true): void
    {
        File::shouldReceive('isFile')
            ->with($this->configFilePath)
            ->once()
            ->andReturn($success)
            ->globally()
            ->ordered();
    }

    private function successfullyCreateConfigFile(bool $success = true): void
    {
        File::shouldReceive('get')->with(base_path("stubs/{$this->fileName }"))
            ->once()
            ->andReturn($this->fileTemplate)
            ->globally()
            ->ordered();

        File::shouldReceive('put')
            ->with($this->configFilePath, $this->fileTemplate)
            ->once()
            ->andReturn($success)
            ->globally()
            ->ordered();
    }

    private function successfullyOpenInEditor(bool $success = true)
    {
        $this->shell->shouldReceive('withTTY')
            ->once()
            ->globally()
            ->andReturnSelf()
            ->ordered();

        $command = "vim {$this->fileName}";
        $expectation = $this->shell->shouldReceive('execIn')
            ->with($this->configDirectory, $command)
            ->once();

        if ($success) {
            $expectation->andReturn(FakeProcess::success());
        } else {
            $expectation->andReturn(FakeProcess::fail($command));
        }

        return $expectation->globally()->ordered();
    }

    private function the_config_directory_does_not_exist()
    {
        File::shouldReceive('isDirectory')
            ->with($this->configDirectory)
            ->once()
            ->andReturn(false)
            ->globally()
            ->ordered();
    }

    private function the_config_directory_is_created()
    {
        File::shouldReceive('makeDirectory')
            ->with($this->configDirectory)
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();
    }

    private function the_config_file_does_not_exist()
    {
        File::shouldReceive('isFile')
            ->with($this->configFilePath)
            ->once()
            ->andReturn(false)
            ->globally()
            ->ordered();
    }

    private function the_config_file_is_created()
    {
        File::shouldReceive('get')->with(base_path("stubs/{$this->fileName }"))
            ->once()
            ->andReturn($this->fileTemplate)
            ->globally()
            ->ordered();

        File::shouldReceive('put')
            ->with($this->configFilePath, $this->fileTemplate)
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();
    }

    private function the_config_file_is_opened_for_editing()
    {
        $this->shell->shouldReceive('withTTY')
            ->once()
            ->globally()
            ->andReturnSelf()
            ->ordered();

        $this->shell->shouldReceive('execIn')
            ->with($this->configDirectory, "vim {$this->fileName}")
            ->once()
            ->andReturn(FakeProcess::success())
            ->globally()
            ->ordered();
    }
}


================================================
FILE: tests/Feature/Fakes/FakeProcess.php
================================================
<?php

namespace Tests\Feature\Fakes;

class FakeProcess
{
    public $isSuccessful;
    public $failedCommand;

    private $output;
    private $errorOutput;

    public function __construct(bool $isSuccessful, string $failedCommand = '')
    {
        $this->isSuccessful = $isSuccessful;
        $this->failedCommand = $failedCommand;
    }

    public static function success(): FakeProcess
    {
        return new self(true);
    }

    public static function fail(string $failedCommand): FakeProcess
    {
        return new self(false, $failedCommand);
    }

    public function isSuccessful(): bool
    {
        return $this->isSuccessful;
    }

    public function getCommandLine(): string
    {
        return $this->failedCommand;
    }

    public function withOutput(string $output): FakeProcess
    {
        $this->output = $output;
        return $this;
    }

    public function withErrorOutput(string $errorOutput): FakeProcess
    {
        $this->errorOutput = $errorOutput;
        return $this;
    }

    public function getOutput()
    {
        return $this->output;
    }

    public function getErrorOutput()
    {
        return $this->errorOutput;
    }

    public function getExitCode()
    {
        return $this->isSuccessful ? 0 : 1;
    }
}


================================================
FILE: tests/Feature/Fixtures/.lambo/commented_configuration
================================================
CODEEDITOR=vim
#QUIET=true
#AUTH=false
#NODE=

# ------------------------------------------------------------------------------
# 1-APR-2020 5:00 am (auto-generated by Lambo):
# Lambo has commented out the configuration items QUIET, AUTH and NODE;
# they are no longer used, and you may safely remove them.
# ------------------------------------------------------------------------------


================================================
FILE: tests/Feature/Fixtures/.lambo/config
================================================
CONFIGURATION_OPTION=foo
#MISSING_CONFIGURATION_OPTION=foo
CONFIGURATION_OPTION_NO_VALUE
CONFIGURATION_OPTION_EMPTY_VALUE=

BOOLEAN_OPTION_1=1
BOOLEAN_OPTION_TRUE=true
BOOLEAN_OPTION_ON=on
BOOLEAN_OPTION_YES=yes
BOOLEAN_OPTION_0=0
BOOLEAN_OPTION_FALSE=false
BOOLEAN_OPTION_OFF=off
BOOLEAN_OPTION_NO=no


================================================
FILE: tests/Feature/Fixtures/.lambo/old_configuration
================================================
CODEEDITOR=vim
QUIET=true
AUTH=false
NODE=


================================================
FILE: tests/Feature/Fixtures/composer-with-laravel-jetstream.json
================================================
{
    "require": {
        "laravel/jetstream": "^1.0"
    }
}


================================================
FILE: tests/Feature/Fixtures/composer-without-laravel-jetstream.json
================================================
{
    "require": {
    }
}


================================================
FILE: tests/Feature/Fixtures/composer.json
================================================
{
    "require": {
        "laravel/jetstream": "^1.0"
    }
}


================================================
FILE: tests/Feature/Fixtures/package-silent.json
================================================
{"scripts":{"development":"cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"}}


================================================
FILE: tests/Feature/Fixtures/package.json
================================================
{
  "scripts": {
    "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
  }
}


================================================
FILE: tests/Feature/GenerateAppKeyTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\GenerateAppKey;
use App\LamboException;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class GenerateAppKeyTest extends TestCase
{
    /** @test */
    function it_generates_a_new_app_key()
    {
        $this->shell->shouldReceive('execInProject')
            ->with('php artisan key:generate --quiet')
            ->once()
            ->andReturn(FakeProcess::success());

        app(GenerateAppKey::class)();
    }

    /** @test */
    function it_throws_an_exception_if_new_app_key_generation_fails()
    {
        $this->shell->shouldReceive('execInProject')
            ->with('php artisan key:generate --quiet')
            ->once()
            ->andReturn(FakeProcess::fail('php artisan key:generate'));

        $this->expectException(LamboException::class);

        app(GenerateAppKey::class)();
    }
}


================================================
FILE: tests/Feature/InitializeGitHubRepositoryTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\Concerns\InteractsWithGitHub;
use App\Actions\InitializeGitHubRepository;
use App\Configuration\LamboConfiguration;
use App\ConsoleWriter;
use App\LamboException;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

/**
 * @group git-and-github
 */
class InitializeGitHubRepositoryTest extends TestCase
{
    use InteractsWithGitHub;

    protected $toolConfigurations = [
        ['gh' => true, 'hub' => true],
        ['gh' => true, 'hub' => false],
        ['gh' => false, 'hub' => true],
        ['gh' => false, 'hub' => false],
    ];

    protected $gitHubConfigurations = [
        [
            LamboConfiguration::GITHUB_PUBLIC => false,
            LamboConfiguration::GITHUB_DESCRIPTION => null,
            LamboConfiguration::GITHUB_HOMEPAGE => null,
            LamboConfiguration::GITHUB_ORGANIZATION => null,
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => false,
            LamboConfiguration::GITHUB_DESCRIPTION => null,
            LamboConfiguration::GITHUB_HOMEPAGE => null,
            LamboConfiguration::GITHUB_ORGANIZATION => 'org',
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => false,
            LamboConfiguration::GITHUB_DESCRIPTION => null,
            LamboConfiguration::GITHUB_HOMEPAGE => 'https://example.com',
            LamboConfiguration::GITHUB_ORGANIZATION => null,
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => false,
            LamboConfiguration::GITHUB_DESCRIPTION => null,
            LamboConfiguration::GITHUB_HOMEPAGE => 'https://example.com',
            LamboConfiguration::GITHUB_ORGANIZATION => 'org',
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => false,
            LamboConfiguration::GITHUB_DESCRIPTION => 'My awesome project',
            LamboConfiguration::GITHUB_HOMEPAGE => null,
            LamboConfiguration::GITHUB_ORGANIZATION => null,
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => false,
            LamboConfiguration::GITHUB_DESCRIPTION => 'My awesome project',
            LamboConfiguration::GITHUB_HOMEPAGE => null,
            LamboConfiguration::GITHUB_ORGANIZATION => 'org',
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => false,
            LamboConfiguration::GITHUB_DESCRIPTION => 'My awesome project',
            LamboConfiguration::GITHUB_HOMEPAGE => 'https://example.com',
            LamboConfiguration::GITHUB_ORGANIZATION => null,
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => false,
            LamboConfiguration::GITHUB_DESCRIPTION => 'My awesome project',
            LamboConfiguration::GITHUB_HOMEPAGE => 'https://example.com',
            LamboConfiguration::GITHUB_ORGANIZATION => 'org',
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => true,
            LamboConfiguration::GITHUB_DESCRIPTION => null,
            LamboConfiguration::GITHUB_HOMEPAGE => null,
            LamboConfiguration::GITHUB_ORGANIZATION => null,
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => true,
            LamboConfiguration::GITHUB_DESCRIPTION => null,
            LamboConfiguration::GITHUB_HOMEPAGE => null,
            LamboConfiguration::GITHUB_ORGANIZATION => 'org',
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => true,
            LamboConfiguration::GITHUB_DESCRIPTION => null,
            LamboConfiguration::GITHUB_HOMEPAGE => 'https://example.com',
            LamboConfiguration::GITHUB_ORGANIZATION => null,
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => true,
            LamboConfiguration::GITHUB_DESCRIPTION => null,
            LamboConfiguration::GITHUB_HOMEPAGE => 'https://example.com',
            LamboConfiguration::GITHUB_ORGANIZATION => 'org',
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => true,
            LamboConfiguration::GITHUB_DESCRIPTION => 'My awesome project',
            LamboConfiguration::GITHUB_HOMEPAGE => null,
            LamboConfiguration::GITHUB_ORGANIZATION => null,
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => true,
            LamboConfiguration::GITHUB_DESCRIPTION => 'My awesome project',
            LamboConfiguration::GITHUB_HOMEPAGE => null,
            LamboConfiguration::GITHUB_ORGANIZATION => 'org',
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => true,
            LamboConfiguration::GITHUB_DESCRIPTION => 'My awesome project',
            LamboConfiguration::GITHUB_HOMEPAGE => 'https://example.com',
            LamboConfiguration::GITHUB_ORGANIZATION => null,
        ],
        [
            LamboConfiguration::GITHUB_PUBLIC => true,
            LamboConfiguration::GITHUB_DESCRIPTION => 'My awesome project',
            LamboConfiguration::GITHUB_HOMEPAGE => 'https://example.com',
            LamboConfiguration::GITHUB_ORGANIZATION => 'org',
        ],
    ];

    /** @test */
    function it_manages_new_repository_initialization()
    {
        foreach ([true, false] as $initializeGitHub) {
            foreach ($this->toolConfigurations as $toolConfiguration) {
                foreach ($this->gitHubConfigurations as $gitHubConfiguration) {
                    config(['lambo.store.project_name' => 'name']);
                    config(['lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB => $initializeGitHub]);
                    config(['lambo.store.push_to_github' => false]);
                    config(['lambo.store.tools' => $toolConfiguration]);
                    config(['lambo.store' => array_merge(config('lambo.store'), $gitHubConfiguration)]);

                    if ($this->shouldCreateRepository()) {
                        $this->shell->shouldReceive('execInProject', [$this->getGitHubCreateCommand()])
                            ->andReturn(FakeProcess::success());
                    }

                    if (! $this->gitHubToolingInstalled()) {
                        $this->expectException(LamboException::class);
                    }

                    app(InitializeGitHubRepository::class)();

                    if ($this->shouldCreateRepository()) {
                        $this->assertTrue(config('lambo.store.push_to_github'));
                    }
                }
            }
        }
    }

    /** @test */
    function it_warns_the_user_if_repository_creation_fails()
    {
        $consoleWriter = $this->mock(ConsoleWriter::class);
        $consoleWriter->shouldReceive('logStep');

        config(['lambo.store.project_name' => 'name']);
        config(['lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB => true]);
        config(['lambo.store.push_to_github' => false]);
        config(['lambo.store.tools.gh' => true]);

        $failedCommandOutput = 'Failed command output';

        $this->shell->shouldReceive('execInProject')
            ->with($this->getGitHubCreateCommand())
            ->once()
            ->andReturn(FakeProcess::fail($this->getGitHubCreateCommand())->withErrorOutput($failedCommandOutput));

        $consoleWriter->shouldReceive('warn')
            ->with(InitializeGitHubRepository::WARNING_FAILED_TO_CREATE_REPOSITORY)
            ->globally()
            ->ordered();

        $consoleWriter->shouldReceive('warnCommandFailed')
            ->with($this->getGitHubCreateCommand())
            ->globally()
            ->ordered();

        $consoleWriter->shouldReceive('showOutputErrors')
            ->with($failedCommandOutput)
            ->globally()
            ->ordered();

        app(InitializeGitHubRepository::class)();
    }
}


================================================
FILE: tests/Feature/InitializeGitRepositoryTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\InitializeGitRepository;
use App\LamboException;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class InitializeGitRepositoryTest extends TestCase
{
    /** @test */
    function it_initializes_git()
    {
        config(['lambo.store.commit_message' => 'Initial commit']);

        $this->shell->shouldReceive('execInProject')
            ->with('git init --quiet')
            ->once()
            ->andReturn(FakeProcess::success());

        $this->shell->shouldReceive('execInProject')
            ->with('git add .')
            ->once()
            ->andReturn(FakeProcess::success());

        $this->shell->shouldReceive('execInProject')
            ->with("git commit --quiet -m 'Initial commit'")
            ->once()
            ->andReturn(FakeProcess::success());

        app(InitializeGitRepository::class)();
    }

    /** @test */
    function it_throws_an_exception_if_git_init_fails()
    {
        $this->shell->shouldReceive('execInProject')
            ->with('git init --quiet')
            ->once()
            ->andReturn(FakeProcess::fail('git init'));

        $this->expectException(LamboException::class);

        app(InitializeGitRepository::class)();
    }

    /** @test */
    function it_throws_an_exception_if_git_add_fails()
    {
        $this->shell->shouldReceive('execInProject')
            ->with('git init --quiet')
            ->once()
            ->andReturn(FakeProcess::success());

        $this->shell->shouldReceive('execInProject')
            ->with('git add .')
            ->once()
            ->andReturn(FakeProcess::fail('git add .'));

        $this->expectException(LamboException::class);

        app(InitializeGitRepository::class)();
    }

    /** @test */
    function it_throws_an_exception_if_git_commit_fails()
    {
        config(['lambo.store.commit_message' => 'Initial commit']);

        $command = 'git init --quiet';
        $this->shell->shouldReceive('execInProject')
            ->with($command)
            ->once()
            ->andReturn(FakeProcess::success());

        $this->shell->shouldReceive('execInProject')
            ->with('git add .')
            ->once()
            ->andReturn(FakeProcess::success());

        $this->shell->shouldReceive('execInProject')
            ->with("git commit --quiet -m 'Initial commit'")
            ->once()
            ->andReturn(FakeProcess::fail('git commit -m "Initial commit"'));

        $this->expectException(LamboException::class);

        app(InitializeGitRepository::class)();
    }

    /** @test */
    function it_removes_the_quiet_flag_when_show_output_is_enabled()
    {
        config(['lambo.store.commit_message' => 'Initial commit']);
        config(['lambo.store.with_output' => true]);

        $this->shell->shouldReceive('execInProject')
            ->with('git init')
            ->once()
            ->andReturn(FakeProcess::success());

        $this->shell->shouldReceive('execInProject')
            ->with('git add .')
            ->once()
            ->andReturn(FakeProcess::success());

        $this->shell->shouldReceive('execInProject')
            ->with("git commit -m 'Initial commit'")
            ->once()
            ->andReturn(FakeProcess::success());

        app(InitializeGitRepository::class)();
    }
}


================================================
FILE: tests/Feature/InstallBreezeTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\InstallBreeze;
use App\LamboException;
use App\Shell;
use Tests\TestCase;

/**
 * @group front-end-scaffolding
 */
class InstallBreezeTest extends TestCase
{
    /**
     * @test
     * @throws LamboException
     */
    function it_installs_laravel_breeze()
    {
        foreach ([false, true] as $withOutput) {
            foreach (InstallBreeze::VALID_STACKS as $stack) {
                config(['lambo.store.breeze' => $stack]);
                config(['lambo.store.with_output' => $withOutput]);

                if ($this->isVerbose()) {
                    $this->logUseCase($stack, $withOutput);
                }

                $this->shouldExecInProject($this->getComposerCommand($withOutput));
                $this->shouldExecInProject($this->getBreezeInstallCommand($stack, $withOutput));
                $this->shouldExecInProject($this->getNpmInstallCommand($withOutput));
                $this->shouldExecInProject($this->getCompileAssetsCommand($withOutput));

                app(InstallBreeze::class)();

                if ($this->isDebug()) {
                    $this->toSTDOUT("\n ✔ PASS\n");
                }
            }
        }
    }

    /**
     * @test
     * @throws LamboException
     */
    function it_skips_breeze_installation()
    {
        $this->spy(Shell::class);
        config(['lambo.store.breeze' => false]);

        app(InstallBreeze::class)();

        $this->shell->shouldNotHaveReceived('execInProject');
    }

    /** @test */
    function it_throws_a_lambo_exception_if_an_invalid_breeze_stack_is_requested()
    {
        config(['lambo.store.breeze' => null]);
        $this->expectException(LamboException::class);
        app(InstallBreeze::class)();

        config(['lambo.store.breeze' => '']);
        $this->expectException(LamboException::class);
        app(InstallBreeze::class)();

        config(['lambo.store.breeze' => 'invalid']);
        $this->expectException(LamboException::class);
        app(InstallBreeze::class)();

        config(['lambo.store.breeze' => true]);
        $this->expectException(LamboException::class);
        app(InstallBreeze::class)();
    }

    /** @test */
    function it_throws_a_lambo_exception_if_composer_installation_fails()
    {
        config(['lambo.store.breeze' => 'blade']);

        $this->shouldExecInProjectAndFail('composer require laravel/breeze --dev --quiet');
        $this->expectException(LamboException::class);

        app(InstallBreeze::class)();
    }

    /** @test */
    function it_throws_a_lambo_exception_if_breeze_installation_fails()
    {
        config(['lambo.store.breeze' => 'react']);

        $this->shouldExecInProject('composer require laravel/breeze --dev --quiet');
        $this->shouldExecInProjectAndFail('php artisan breeze:install react --quiet');

        $this->expectException(LamboException::class);

        app(InstallBreeze::class)();
    }

    private function getComposerCommand(bool $withOutput = false): string
    {
        return 'composer require laravel/breeze --dev' . ($withOutput ? '' : ' --quiet');
    }

    private function getBreezeInstallCommand(string $stack, $showOutput): string
    {
        return sprintf(
            'php artisan breeze:install%s%s',
            $stack === 'blade' ? '' : " {$stack}",
            $showOutput ? '' : ' --quiet'
        );
    }

    private function getNpmInstallCommand($showOutput): string
    {
        return 'npm install' . ($showOutput ? '' : ' --silent');
    }

    private function getCompileAssetsCommand($withOutput): string
    {
        return 'npm run build' . ($withOutput ? '' : ' --silent');
    }

    private function logUseCase(string $stack, $showOutput): void
    {
        $showOutputStr = $showOutput ? 'true' : 'false';

        $this->toSTDOUT("────────────────────────────\n");
        $this->toSTDOUT(implode(PHP_EOL, [
            sprintf('   lambo new <project> %s--breeze=%s', $showOutput ? '-v(vv) ' : '', $stack),
        ]), ' USE CASE');
        $this->toSTDOUT(implode(PHP_EOL, [
            "   1. {$this->getComposerCommand($showOutput)}",
            "   2. {$this->getBreezeInstallCommand($stack, $showOutput)}",
            "   3. {$this->getNpmInstallCommand($showOutput)}",
            "   4. {$this->getCompileAssetsCommand($showOutput)}",
        ]), ' COMMAND EXECUTION ORDER');
        $this->toSTDOUT(implode(PHP_EOL, [
            "   \$stack : {$stack}",
            "   \$showOutput : {$showOutputStr}",
            '   config(lambo.store.breeze) : ' . config('lambo.store.breeze'),
            '   config(lambo.store.show_output) : ' . (config('lambo.store.show_output') ? 'true' : 'false'),
        ]), ' TEST ITERATION CONTEXT');
    }
}


================================================
FILE: tests/Feature/InstallJetstreamTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\InstallJetstream;
use App\LamboException;
use App\Shell;
use Tests\TestCase;

/**
 * @group front-end-scaffolding
 */
class InstallJetstreamTest extends TestCase
{
    /**
     * @test
     * @throws LamboException
     */
    function it_installs_laravel_jetstream()
    {
        foreach ([false, true] as $withOutput) {
            foreach ([false, true] as $useTeams) {
                foreach (InstallJetstream::VALID_STACKS as $stack) {
                    config(['lambo.store.jetstream' => $stack]);
                    config(['lambo.store.with_output' => $withOutput]);

                    if ($this->isDebug()) {
                        $this->logUseCase($stack, $useTeams, $withOutput);
                    }

                    $this->shouldExecInProject($this->getComposerCommand($withOutput));
                    $this->shouldExecInProject($this->getJetstreamInstallCommand($stack, $withOutput));
                    $this->shouldExecInProject($this->getNpmInstallCommand($withOutput));
                    $this->shouldExecInProject($this->getCompileAssetsCommand($withOutput));

                    app(InstallJetstream::class)();

                    if ($this->isDebug()) {
                        $this->toSTDOUT("\n ✔ PASS\n");
                    }
                }
            }
        }
    }

    /**
     * @test
     * @throws LamboException
     */
    function it_skips_jetstream_installation()
    {
        $this->spy(Shell::class);
        config(['lambo.store.jetstream' => false]);

        app(InstallJetstream::class)();

        $this->shell->shouldNotHaveReceived('execInProject');
    }

    /** @test */
    function it_throws_a_lambo_exception_if_an_invalid_jetstream_stack_is_requested()
    {
        config(['lambo.store.jetstream' => null]);
        $this->expectException(LamboException::class);
        app(InstallJetstream::class)();

        config(['lambo.store.jetstream' => '']);
        $this->expectException(LamboException::class);
        app(InstallJetstream::class)();

        config(['lambo.store.jetstream' => 'invalid']);
        $this->expectException(LamboException::class);
        app(InstallJetstream::class)();

        config(['lambo.store.jetstream' => true]);
        $this->expectException(LamboException::class);
        app(InstallJetstream::class)();
    }

    /** @test */
    function it_throws_a_lambo_exception_if_composer_installation_fails()
    {
        config(['lambo.store.jetstream' => 'inertia']);

        $this->shouldExecInProjectAndFail('composer require laravel/jetstream --dev --quiet');
        $this->expectException(LamboException::class);

        app(InstallJetstream::class)();
    }

    /** @test */
    function it_throws_a_lambo_exception_if_jetstream_installation_fails()
    {
        config(['lambo.store.jetstream' => 'inertia']);

        $this->shouldExecInProject('composer require laravel/jetstream --dev --quiet');
        $this->shouldExecInProjectAndFail('php artisan jetstream:install inertia --quiet');
        $this->expectException(LamboException::class);

        app(InstallJetstream::class)();
    }

    private function getJetstreamInstallCommand(string $stack, $showOutput): string
    {
        return "php artisan jetstream:install {$stack}" . ($showOutput ? '' : ' --quiet');
    }

    private function getNpmInstallCommand($showOutput): string
    {
        return 'npm install' . ($showOutput ? '' : ' --silent');
    }

    private function getComposerCommand(bool $withOutput = false): string
    {
        return 'composer require laravel/jetstream --dev' . ($withOutput ? '' : ' --quiet');
    }

    private function getCompileAssetsCommand($withOutput): string
    {
        return 'npm run build' . ($withOutput ? '' : ' --silent');
    }

    private function logUseCase(string $stack, $useTeams, $showOutput): void
    {
        $useTeamsStr = $useTeams ? 'true' : 'false';
        $showOutputStr = $showOutput ? 'true' : 'false';

        $configStack = config('lambo.store.jetstream');
        $configShowOutputStr = config('lambo.store.show_output') ? 'true' : 'false';

        $this->toSTDOUT("────────────────────────────\n");
        $this->toSTDOUT(sprintf(
            " USE CASE\n   lambo new <project> %s--jetstream=%s%s",
            $showOutput ? '-v[vv] ' : '',
            $stack,
            $useTeams ? ',teams' : ''
        ));
        $this->toSTDOUT(implode(PHP_EOL, [
            "   1. {$this->getComposerCommand($showOutput)}",
            "   2. {$this->getJetstreamInstallCommand($stack, $showOutput)}",
            "   3. {$this->getNpmInstallCommand($showOutput)}",
            "   4. {$this->getCompileAssetsCommand($showOutput)}",
        ]), ' COMMAND EXECUTION ORDER');
        $this->toSTDOUT(implode(PHP_EOL, [
            "   \$stack : {$stack}",
            "   \$useTeams : {$useTeamsStr}",
            "   \$showOutput : {$showOutputStr}",
            "   config(lambo.store.jetstream) : {$configStack}",
            "   config(lambo.store.show_output) : {$configShowOutputStr}",
        ]), ' TEST ITERATION CONTEXT');
    }
}


================================================
FILE: tests/Feature/InstallLaravelTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\InstallLaravel;
use App\LamboException;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class InstallLaravelTest extends TestCase
{
    /** @test */
    function it_installs_laravel()
    {
        collect([
            ['lambo.store.dev' => false, 'lambo.store.with_output' => false],
            ['lambo.store.dev' => false, 'lambo.store.with_output' => true],
            ['lambo.store.dev' => true, 'lambo.store.with_output' => false],
            ['lambo.store.dev' => true, 'lambo.store.with_output' => true],
        ])->each(function ($options) {
            config(['lambo.store.project_name' => 'my-project']);
            config(['lambo.store.dev' => $options['lambo.store.dev']]);
            config(['lambo.store.with_output' => $options['lambo.store.with_output']]);
            $this->shell->shouldReceive('execInRoot')
                ->with(sprintf(
                    'composer create-project laravel/laravel %s%s --remove-vcs --prefer-dist %s',
                    config('lambo.store.project_name'),
                    config('lambo.store.dev') ? ' dev-master' : '',
                    config('lambo.store.with_output') ? '' : '--quiet'
                ))
                ->once()
                ->andReturn(FakeProcess::success());

            app(InstallLaravel::class)();
        });
    }

    /** @test */
    function it_throws_an_exception_if_laravel_fails_to_install()
    {
        config(['lambo.store.project_name' => 'my-project']);
        config(['lambo.store.dev' => false]);
        config(['lambo.store.with_output' => false]);

        $this->shell->shouldReceive('execInRoot')
            ->andReturn(FakeProcess::fail('failed command'));

        $this->expectException(LamboException::class);

        app(InstallLaravel::class)();
    }
}


================================================
FILE: tests/Feature/InstallNpmDependenciesTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\InstallNpmDependencies;
use App\LamboException;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class InstallNpmDependenciesTest extends TestCase
{
    /** @test */
    function it_installs_npm_dependencies()
    {
        config(['lambo.store.with_output' => false]);

        $this->shell->shouldReceive('execInProject')
            ->with('npm install --silent')
            ->once()
            ->andReturn(FakeProcess::success());

        app(InstallNpmDependencies::class)();
    }

    /** @test */
    function it_installs_npm_dependencies_and_shows_console_output()
    {
        config(['lambo.store.with_output' => true]);

        $this->shell->shouldReceive('execInProject')
            ->with('npm install')
            ->once()
            ->andReturn(FakeProcess::success());

        app(InstallNpmDependencies::class)();
    }

    /** @test */
    function it_throws_an_exception_if_npm_install_fails()
    {
        config(['lambo.store.with_output' => false]);

        $this->shell->shouldReceive('execInProject')
            ->with('npm install --silent')
            ->once()
            ->andReturn(FakeProcess::fail('npm install --silent'));

        $this->expectException(LamboException::class);

        app(InstallNpmDependencies::class)();
    }
}


================================================
FILE: tests/Feature/LamboTestEnvironment.php
================================================
<?php

namespace Tests\Feature;

use Illuminate\Support\Facades\File;

trait LamboTestEnvironment
{
    protected function withValetTld($tld = 'test'): void
    {
        $valetConfig = config('home_dir') . '/.config/valet/config.json';

        File::shouldReceive('isFile')
            ->with($valetConfig)
            ->andReturnTrue();

        File::shouldReceive('get')
            ->with($valetConfig)
            ->andReturn(sprintf('{"tld": "%s"}', $tld));
    }
}


================================================
FILE: tests/Feature/MigrateDatabaseTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\MigrateDatabase;
use App\Shell;
use App\Tools\Database;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class MigrateDatabaseTest extends TestCase
{
    private $database;

    public function setUp(): void
    {
        parent::setUp();
        $this->database = $this->mock(Database::class);
    }

    /** @test */
    function it_migrates_the_database()
    {
        $fakeStore = [
            'migrate_database' => true,
            'database_host' => 'example.test',
            'database_port' => 3306,
            'database_username' => 'user',
            'database_password' => 'password',
            'database_name' => 'foo',
        ];

        config(['lambo.store' => $fakeStore]);

        $this->database->shouldReceive('fillFromLamboStore')
            ->with($fakeStore)
            ->once()
            ->andReturnSelf();

        $this->database->shouldReceive('ensureExists')
            ->once()
            ->andReturnTrue();

        $this->shell->shouldReceive('execInProject')
            ->with('php artisan migrate --quiet')
            ->once()
            ->andReturn(FakeProcess::success());

        app(MigrateDatabase::class)();
    }

    /** @test */
    function failed_migrations_do_not_halt_execution()
    {
        $fakeStore = [
            'migrate_database' => true,
            'database_host' => 'example.test',
            'database_port' => 3306,
            'database_username' => 'user',
            'database_password' => 'password',
            'database_name' => 'foo',
        ];

        config(['lambo.store' => $fakeStore]);

        $this->database->shouldReceive('fillFromLamboStore')
            ->with($fakeStore)
            ->once()
            ->andReturnSelf();

        $this->database->shouldReceive('ensureExists')
            ->once()
            ->andReturnTrue();

        $this->shell->shouldReceive('execInProject')
            ->with('php artisan migrate --quiet')
            ->once()
            ->andReturn(FakeProcess::fail('php artisan migrate --quiet'));

        app(MigrateDatabase::class)();
    }

    /** @test */
    function it_skips_migrations()
    {
        $databaseSpy = $this->spy(Database::class);
        $shellSpy = $this->spy(Shell::class);

        // Mock the Database->url() so that if it is called it
        // returns properly.
        $databaseSpy->shouldReceive('url')->andReturnSelf();

        config(['lambo.store.migrate_database' => false]);

        config(['lambo.store.database_host' => 'example.test']);
        config(['lambo.store.database_port' => 3306]);
        config(['lambo.store.database_username' => 'user']);
        config(['lambo.store.database_password' => 'password']);
        config(['lambo.store.database_name' => 'foo']);

        app(MigrateDatabase::class)();

        $databaseSpy->shouldNotHaveReceived('fillFromLamboStore');
        $databaseSpy->shouldNotHaveReceived('ensureExists');
        $shellSpy->shouldNotHaveReceived('execInProject');
    }
}


================================================
FILE: tests/Feature/OpenInBrowserTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\OpenInBrowser;
use App\Environment;
use App\Shell;
use Tests\TestCase;

class OpenInBrowserTest extends TestCase
{
    private $environment;

    public function setUp(): void
    {
        parent::setUp();
        $this->environment = $this->mock(Environment::class);
    }

    /** @test */
    function it_uses_the_open_command_on_mac_when_a_browser_is_specified()
    {
        config(['lambo.store.browser' => '/Applications/my/browser.app']);
        config(['lambo.store.project_url' => 'http://my-project.test']);

        $this->environment->shouldReceive('isMac')
            ->once()
            ->andReturn(true);

        $this->shell->shouldReceive('execInProject')
            ->once()
            ->with('open -a "/Applications/my/browser.app" "http://my-project.test"');

        app(OpenInBrowser::class)();
    }

    /** @test */
    function it_uses_valet_open_on_mac_when_no_browser_is_specified()
    {
        $this->assertEmpty(config('lambo.store.browser'));

        $this->environment->shouldReceive('isMac')
            ->once()
            ->andReturn(true);

        $this->shell->shouldReceive('execInProject')
            ->once()
            ->with('valet open');

        app(OpenInBrowser::class)();
    }

    /** @test */
    function it_uses_valet_open_when_not_running_on_mac()
    {
        $this->environment->shouldReceive('isMac')
            ->once()
            ->andReturn(false);

        $this->shell->shouldReceive('execInProject')
            ->once()
            ->with('valet open');

        app(OpenInBrowser::class)();
    }

    /** @test */
    function it_ignores_the_specified_browser_when_not_running_on_mac()
    {
        config(['lambo.store.browser' => '/path/to/a/browser']);
        config(['lambo.store.project_url' => 'http://my-project.test']);

        $this->environment->shouldReceive('isMac')
            ->once()
            ->andReturn(false);

        $this->shell->shouldReceive('execInProject')
            ->once()
            ->with('valet open');

        app(OpenInBrowser::class)();
    }

    /** @test */
    function it_skips_opening_the_site()
    {
        $shell = $this->spy(Shell::class);

        config(['lambo.store.no_browser' => false]);

        app(OpenInBrowser::class);

        $shell->shouldNotHaveReceived('execInProject');
    }
}


================================================
FILE: tests/Feature/OpenInEditorTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\OpenInEditor;
use App\LamboException;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class OpenInEditorTest extends TestCase
{
    /** @test */
    function it_opens_the_project_folder_in_the_specified_editor()
    {
        config(['lambo.store.editor' => 'my-editor']);

        $this->shell->shouldReceive('withTTY')
            ->once()
            ->andReturnSelf();

        $this->shell->shouldReceive('execInProject')
            ->with('my-editor .')
            ->once()
            ->andReturn(FakeProcess::success());

        app(OpenInEditor::class)();
    }

    /** @test */
    function it_throws_an_exception_if_it_fails_to_open_the_editor()
    {
        config(['lambo.store.editor' => 'my-editor']);

        $this->shell->shouldReceive('withTTY')
            ->once()
            ->andReturnSelf();

        $this->shell->shouldReceive('execInProject')
            ->with('my-editor .')
            ->once()
            ->andReturn(FakeProcess::fail('my-editor .'));

        $this->expectException(LamboException::class);

        app(OpenInEditor::class)();
    }
}


================================================
FILE: tests/Feature/PushToGitHubTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\PushToGitHub;
use App\ConsoleWriter;
use App\Shell;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

/**
 * @group git-and-github
 */
class PushToGitHubTest extends TestCase
{
    private $consoleWriter;

    /** @test */
    function it_pushes_to_github()
    {
        config(['lambo.store.push_to_github' => true]);

        $this->shell->shouldReceive('execInProject')
            ->with('git rev-parse --abbrev-ref HEAD')
            ->once()
            ->andReturn(FakeProcess::success()->withOutput('main'))
            ->globally()
            ->ordered();

        $this->shell->shouldReceive('execInProject')
            ->with('git push -u origin main')
            ->once()
            ->andReturn(FakeProcess::success());

        app(PushToGitHub::class)();
    }

    /** @test */
    function it_logs_a_warning_if_branch_name_cannot_be_determined()
    {
        $this->consoleWriter = $this->mock(ConsoleWriter::class);

        config(['lambo.store.push_to_github' => true]);

        $this->shouldLogStep('Pushing new project to GitHub');

        $getBranchNameCommand = 'git rev-parse --abbrev-ref HEAD';
        $errorMessage = 'Oops, something went wrong.';
        $failedBranchNameProcess = FakeProcess::fail($getBranchNameCommand)
            ->withErrorOutput($errorMessage);

        $this->shell->shouldReceive('execInProject')
            ->with($getBranchNameCommand)
            ->once()
            ->andReturn($failedBranchNameProcess)
            ->globally()
            ->ordered();

        $this->shouldLogWarning(PushToGitHub::WARNING_UNABLE_TO_GET_BRANCH_NAME);
        $this->shouldLogWarning("Failed to run {$getBranchNameCommand}");
        $this->shouldShowOutputErrors($errorMessage);

        app(PushToGitHub::class)();
    }

    /** @test */
    function it_logs_a_warning_if_pushing_to_git_hub_fails()
    {
        $this->consoleWriter = $this->mock(ConsoleWriter::class);

        config(['lambo.store.push_to_github' => true]);

        $this->shouldLogStep('Pushing new project to GitHub');

        $branchNameProcess = FakeProcess::success()->withOutput('main');
        $this->shell->shouldReceive('execInProject')
            ->with('git rev-parse --abbrev-ref HEAD')
            ->once()
            ->andReturn($branchNameProcess)
            ->globally()
            ->ordered();

        $pushToGitHubCommand = "git push -u origin {$branchNameProcess->getOutput()}";
        $errorMessage = 'Oops, something went wrong.';
        $failedPushToGitHubProcess = FakeProcess::fail($pushToGitHubCommand)
            ->withErrorOutput($errorMessage);

        $this->shell->shouldReceive('execInProject')
            ->with($pushToGitHubCommand)
            ->once()
            ->andReturn($failedPushToGitHubProcess)
            ->globally()
            ->ordered();

        $this->shouldLogWarning(PushToGitHub::WARNING_FAILED_TO_PUSH);
        $this->shouldLogWarning("Failed to run {$pushToGitHubCommand}");
        $this->shouldShowOutputErrors($errorMessage);

        app(PushToGitHub::class)();
    }

    /** @test */
    function it_skips_pushing_to_github()
    {
        $shell = $this->spy(Shell::class);

        $pushCommand = 'git push -u origin ';

        config(['lambo.store.push_to_github' => null]);
        app(PushToGitHub::class)();
        $shell->shouldNotHaveReceived('execInProject', [$pushCommand]);

        config(['lambo.store.push_to_github' => false]);
        app(PushToGitHub::class)();
        $shell->shouldNotHaveReceived('execInProject', [$pushCommand]);
    }

    private function shouldLogWarning(string $warning): void
    {
        $this->consoleWriter->shouldReceive('warn')
            ->with($warning)
            ->globally()
            ->ordered();
    }

    private function shouldLogStep(string $step)
    {
        $this->consoleWriter->shouldReceive('logStep')
            ->with($step)
            ->globally()
            ->ordered();
    }

    private function shouldShowOutputErrors(string $error)
    {
        $this->consoleWriter->shouldReceive('showOutputErrors')
            ->with($error)
            ->globally()
            ->ordered();
    }
}


================================================
FILE: tests/Feature/RunAfterScriptTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\RunAfterScript;
use App\LamboException;
use Illuminate\Support\Facades\File;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class RunAfterScriptTest extends TestCase
{
    function setUp(): void
    {
        parent::setUp();
        config(['home_dir' => $this->getHomeDirectory()]);
        config(['lambo.store.project_path' => $this->getProjectPath()]);
    }

    /** @test */
    function it_runs_the_after_script_if_one_exists()
    {
        File::shouldReceive('isFile')
            ->with($this->getAfterScriptPath())
            ->andReturn(true)
            ->globally()
            ->ordered();

        $this->shell->shouldReceive('withTTY')
            ->once()
            ->globally()
            ->ordered();

        $this->shell->shouldReceive('execInProject')
            ->with($this->getCommand())
            ->once()
            ->andReturn(FakeProcess::success())
            ->globally()
            ->ordered();

        app(RunAfterScript::class)();
    }

    /** @test */
    function it_throws_an_exception_if_the_after_script_fails()
    {
        File::shouldReceive('isFile')
            ->with($this->getAfterScriptPath())
            ->andReturn(true)
            ->globally()
            ->ordered();

        $this->shell->shouldReceive('withTTY')
            ->once()
            ->globally()
            ->ordered();

        $this->shell->shouldReceive('execInProject')
            ->with($this->getCommand())
            ->once()
            ->andReturn(FakeProcess::fail($this->getCommand()))
            ->globally()
            ->ordered();

        $this->expectException(LamboException::class);

        app(RunAfterScript::class)();
    }

    private function getAfterScriptPath(): string
    {
        return "{$this->getHomeDirectory()}/.lambo/after";
    }

    private function getHomeDirectory(): string
    {
        return '/my/home/dir';
    }

    private function getCommand(): string
    {
        return sprintf('env PROJECTPATH=%s sh %s', $this->getProjectPath(), $this->getAfterScriptPath());
    }

    private function getProjectPath(): string
    {
        return '/my/project/path';
    }
}


================================================
FILE: tests/Feature/SignatureBuilderTest.php
================================================
<?php

namespace Tests\Feature;

use App\Commands\NewCommand;
use Tests\TestCase;

class SignatureBuilderTest extends TestCase
{
    /** @test */
    function it_offers_short_and_long_codes()
    {
        $newCommand = new NewCommand();
        $output = $newCommand->buildSignatureOption([
            'short' => 'e',
            'long' => 'editor',
            'cli_description' => '',
        ]);

        $this->assertStringContainsString('-e|editor', $output);
    }

    /** @test */
    function it_functions_given_only_long_code()
    {
        $newCommand = new NewCommand();
        $output = $newCommand->buildSignatureOption([
            'long' => 'editor',
            'cli_description' => '',
        ]);

        $this->assertStringContainsString('-editor', $output);
    }

    /** @test */
    function it_sets_expectation_for_values_if_option_expects_parameters()
    {
        $newCommand = new NewCommand();
        $output = $newCommand->buildSignatureOption([
            'long' => 'editor',
            'param_description' => 'a',
            'cli_description' => '',
        ]);

        $this->assertStringContainsString('-editor=', $output);
    }

    /** @test */
    function it_does_not_set_expectation_for_values_if_option_does_not_expect_parameters()
    {
        $newCommand = new NewCommand();
        $output = $newCommand->buildSignatureOption([
            'long' => 'editor',
            'cli_description' => '',
        ]);

        $this->assertStringNotContainsString('editor=', $output);
    }

    /** @test */
    function it_defines_description()
    {
        $newCommand = new NewCommand();
        $output = $newCommand->buildSignatureOption([
            'long' => 'editor',
            'cli_description' => 'The Option Description',
        ]);

        $this->assertStringContainsString('The Option Description', $output);
    }
}


================================================
FILE: tests/Feature/UpgradeSavedConfigurationTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\UpgradeSavedConfiguration;
use Carbon\Carbon;
use Tests\TestCase;

class UpgradeSavedConfigurationTest extends TestCase
{
    private $validConfigurationKeys = [
        'VALID_KEY',
        'ANOTHER_VALID_KEY',
    ];

    private $removedConfigurationKeys = [
        'OLD_KEY',
        'ANOTHER_OLD_KEY',
    ];

    private $newConfiguration = [
        'THING' => [
            'commented' => true,
            'default' => 'flibble',
            'description' => [
                'The THING parameter enables Lambo to do a thing.',
                'Valid options are foo, bar and flibble (default if not specified).',
            ],
        ],
        'ANOTHER_THING' => [
            'commented' => false,
            'default' => 'false',
            'description' => [
                'The ANOTHER_THING parameter enables Lambo to do a another thing.',
                'Valid options are true or false (default if not specified).',
            ],
        ],
    ];

    /** @test */
    function it_upgrades_saved_configuration()
    {
        $this->travelTo(Carbon::parse('01-Jan-2000 00:00:00', config('app.timezone')));

        $upgradedConfiguration = app(UpgradeSavedConfiguration::class)->upgrade($this->getConfiguration(), $this->removedConfigurationKeys, $this->newConfiguration);

        $commented =
        'VALID_KEY=foo
ANOTHER_VALID_KEY=foo
#OLD_KEY=foo
#ANOTHER_OLD_KEY=foo


# ------------------------------------------------------------------------------
# 1-Jan-2000 12:00 am (auto-generated by Lambo):
# ------------------------------------------------------------------------------
# Lambo has commented out the following configuration items as they
# are no-longer used. You may safely remove them:
#   OLD_KEY=foo
#   ANOTHER_OLD_KEY=foo

# Lambo has introduced new configuration options. They have been added here
# with sensible defaults; however, you should review them.
#
# The THING parameter enables Lambo to do a thing.
# Valid options are foo, bar and flibble (default if not specified).
#THING=flibble

# The ANOTHER_THING parameter enables Lambo to do a another thing.
# Valid options are true or false (default if not specified).
ANOTHER_THING=false

';

        $this->assertEquals(
            $commented,
            $upgradedConfiguration
        );
    }

    private function getConfiguration(): string
    {
        return collect(array_merge($this->validConfigurationKeys, $this->removedConfigurationKeys))->reduce(function ($carry, $configurationKey) {
            return "{$carry}{$configurationKey}=foo\n";
        }, '');
    }
}


================================================
FILE: tests/Feature/ValetLinkTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\ValetLink;
use App\LamboException;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class ValetLinkTest extends TestCase
{
    /** @test */
    function it_runs_valet_link()
    {
        config(['lambo.store.valet_link' => true]);

        $this->shell->shouldReceive('execInProject')
            ->with('valet link')
            ->once()
            ->andReturn(FakeProcess::success());

        app(ValetLink::class)();
    }

    /** @test */
    function it_throws_an_exception_if_valet_link_fails()
    {
        config(['lambo.store.valet_link' => true]);

        $command = 'valet link';
        $this->shell->shouldReceive('execInProject')
            ->with($command)
            ->once()
            ->andReturn(FakeProcess::fail($command));

        $this->expectException(LamboException::class);

        app(ValetLink::class)();
    }
}


================================================
FILE: tests/Feature/ValetSecureTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\ValetSecure;
use App\LamboException;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

class ValetSecureTest extends TestCase
{
    /** @test */
    function it_runs_valet_secure()
    {
        config(['lambo.store.valet_secure' => true]);

        $this->shell->shouldReceive('execInProject')
            ->with('valet secure')
            ->once()
            ->andReturn(FakeProcess::success());

        app(ValetSecure::class)();
    }

    /** @test */
    function it_throws_an_exception_if_valet_secure_fails()
    {
        config(['lambo.store.valet_secure' => true]);

        $this->shell->shouldReceive('execInProject')
            ->with('valet secure')
            ->once()
            ->andReturn(FakeProcess::fail('valet secure'));

        $this->expectException(LamboException::class);

        app(ValetSecure::class)();
    }
}


================================================
FILE: tests/Feature/ValidateGitHubConfigurationTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\ValidateGitHubConfiguration;
use App\Configuration\LamboConfiguration;
use App\ConsoleWriter;
use LaravelZero\Framework\Commands\Command;
use Tests\Feature\Fakes\FakeProcess;
use Tests\TestCase;

/**
 * @group git-and-github
 */
class ValidateGitHubConfigurationTest extends TestCase
{
    private $consoleWriter;
    private $console;

    /** @test */
    function it_skips_gh_command_line_tool_validation()
    {
        config(['lambo.store.tools.gh' => true]);
        config(['lambo.store.tools.hub' => true]);

        config(['lambo.store.initializeGitHub' => null]);
        app(ValidateGitHubConfiguration::class)();
        $this->assertFalse(config('lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB));

        config(['lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB => false]);
        app(ValidateGitHubConfiguration::class)();
        $this->assertFalse(config('lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB));
    }

    /** @test */
    function it_logs_a_warning_if_github_tooling_is_missing()
    {
        $this->consoleWriter = $this->mock(ConsoleWriter::class);
        $this->console = $this->mock(Command::class);

        config(['lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB => true]);
        config(['lambo.store.tools.gh' => false]);
        config(['lambo.store.tools.hub' => false]);

        $this->shouldLogWarning();
        $this->shouldLogInstructions(ValidateGitHubConfiguration::INSTRUCTIONS_GITHUB_TOOLING_MISSING);
        $this->shouldAskToContinue();

        app(ValidateGitHubConfiguration::class)();

        $this->assertFalse(config('lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB));
    }

    /** @test */
    function configuration_is_valid_if_hub_is_installed()
    {
        $this->consoleWriter = $this->mock(ConsoleWriter::class);

        config(['lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB => true]);
        config(['lambo.store.tools.gh' => true]);
        config(['lambo.store.tools.hub' => true]);

        $this->shouldLogChosenGitHubTool('hub');

        app(ValidateGitHubConfiguration::class)();

        $this->assertTrue(config('lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB));
    }

    /** @test */
    function configuration_is_valid_if_gh_is_installed_and_authenticated()
    {
        $this->consoleWriter = $this->mock(ConsoleWriter::class);

        config(['lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB => true]);
        config(['lambo.store.tools.gh' => true]);
        config(['lambo.store.tools.hub' => false]);

        $this->shell->shouldReceive('execQuietly')
            ->with('gh auth status')
            ->andReturn(FakeProcess::success());

        $this->shouldLogChosenGitHubTool('gh');

        app(ValidateGitHubConfiguration::class)();

        $this->assertTrue(config('lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB));
    }

    /** @test */
    function it_logs_a_warning_if_gh_is_not_authenticated_with_github()
    {
        $this->consoleWriter = $this->mock(ConsoleWriter::class);
        $this->console = $this->mock(Command::class);

        config(['lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB => true]);
        config(['lambo.store.tools.gh' => true]);
        config(['lambo.store.tools.hub' => false]);

        $this->shell->shouldReceive('execQuietly')
            ->with('gh auth status')
            ->andReturn(FakeProcess::fail('gh auth status'));

        $this->shouldLogWarning();
        $this->shouldLogInstructions(ValidateGitHubConfiguration::INSTRUCTIONS_GH_NOT_AUTHENTICATED);
        $this->shouldAskToContinue();

        app(ValidateGitHubConfiguration::class)();

        $this->assertFalse(config('lambo.store.' . LamboConfiguration::INITIALIZE_GITHUB));
    }

    private function shouldLogChosenGitHubTool(string $tool): void
    {
        $this->consoleWriter->shouldReceive('note')
            ->with(sprintf(ValidateGitHubConfiguration::SELECTED_GITHUB_TOOL_MESSAGE_PATTERN, $tool))
            ->globally()
            ->ordered();
    }

    private function shouldLogWarning(): void
    {
        $this->consoleWriter->shouldReceive('warn')
            ->with(ValidateGitHubConfiguration::WARNING_UNABLE_TO_CREATE_REPOSITORY)
            ->globally()
            ->ordered();
    }

    private function shouldAskToContinue(): void
    {
        $this->console->shouldReceive('confirm')
            ->with(ValidateGitHubConfiguration::QUESTION_SHOULD_CONTINUE)
            ->andReturnTrue()
            ->globally()
            ->ordered();
        $this->swap('console', $this->console);
    }

    private function shouldLogInstructions(array $instructions): void
    {
        $this->consoleWriter->shouldReceive('text')
            ->with($instructions)
            ->globally()
            ->ordered();
    }
}


================================================
FILE: tests/Feature/VerifyDependenciesTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\VerifyDependencies;
use App\LamboException;
use Symfony\Component\Process\ExecutableFinder;
use Tests\TestCase;

class VerifyDependenciesTest extends TestCase
{
    private $executableFinder;

    public function setUp(): void
    {
        parent::setUp();
        $this->executableFinder = $this->mock(ExecutableFinder::class);
    }

    /** @test */
    function it_checks_that_dependencies_are_available()
    {
        foreach (['composer', 'valet', 'git', 'hub', 'gh'] as $dependency) {
            $this->dependencyIsAvailable($dependency);
        }

        app(VerifyDependencies::class)();
        $this->assertTrue(config('lambo.store.tools.gh'));
        $this->assertTrue(config('lambo.store.tools.hub'));
    }

    /** @test */
    function it_marks_optional_dependencies_as_missing()
    {
        foreach (['composer', 'valet', 'git'] as $dependency) {
            $this->dependencyIsAvailable($dependency);
        }

        $this->dependencyIsMissing('gh');
        $this->dependencyIsMissing('hub');

        app(VerifyDependencies::class)();
        $this->assertFalse(config('lambo.store.tools.gh'));
        $this->assertFalse(config('lambo.store.tools.hub'));
    }

    /** @test */
    function it_throws_a_lambo_exception_if_composer_is_missing()
    {
        foreach (['valet', 'git', 'hub', 'gh'] as $dependency) {
            $this->dependencyIsAvailable($dependency);
        }

        $this->dependencyIsMissing('composer');

        $this->expectException(LamboException::class);

        app(VerifyDependencies::class)();
    }

    /** @test */
    function it_throws_a_lambo_exception_if_valet_is_missing()
    {
        foreach (['composer', 'git', 'hub', 'gh'] as $dependency) {
            $this->dependencyIsAvailable($dependency);
        }

        $this->dependencyIsMissing('valet');

        $this->expectException(LamboException::class);

        app(VerifyDependencies::class)();
    }

    /** @test */
    function it_throws_a_lambo_exception_if_git_is_missing()
    {
        foreach (['composer', 'valet', 'hub', 'gh'] as $dependency) {
            $this->dependencyIsAvailable($dependency);
        }

        $this->dependencyIsMissing('git');

        $this->expectException(LamboException::class);

        app(VerifyDependencies::class)();
    }

    private function dependencyIsAvailable(string $dependency, $isAvailable = true): void
    {
        $foo = $this->executableFinder
            ->shouldReceive('find')
            ->with($dependency);

        $isAvailable
            ? $foo->andReturn("/path/to/{$dependency}")
            : $foo->andReturnNull();
    }

    private function dependencyIsMissing(string $dependency)
    {
        $this->dependencyIsAvailable($dependency, false);
    }
}


================================================
FILE: tests/Feature/VerifyPathAvailableTest.php
================================================
<?php

namespace Tests\Feature;

use App\Actions\VerifyPathAvailable;
use App\LamboException;
use Exception;
use Illuminate\Support\Facades\File;
use Tests\TestCase;

class VerifyPathAvailableTest extends TestCase
{
    /** @test */
    function it_checks_if_the_required_directories_are_available()
    {
        config(['lambo.store.root_path' => '/some/filesystem/path']);
        config(['lambo.store.project_path' => '/some/filesystem/path/my-project']);

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path')
            ->once()
            ->andReturn(true);

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path/my-project')
            ->once()
            ->andReturn(false);

        app(VerifyPathAvailable::class)();
    }

    /** @test */
    function it_throws_a_lambo_exception_if_the_root_path_is_not_available()
    {
        config(['lambo.store.root_path' => '/non/existent/filesystem/path']);

        File::shouldReceive('isDirectory')
            ->with('/non/existent/filesystem/path')
            ->once()
            ->andReturn(false);

        $this->expectException(LamboException::class);

        app(VerifyPathAvailable::class)();
    }

    /** @test */
    function it_throws_a_lambo_exception_if_the_project_path_already_exists()
    {
        config(['lambo.store.root_path' => '/some/filesystem/path']);
        config(['lambo.store.project_path' => '/some/filesystem/path/existing-directory']);

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path')
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path/existing-directory')
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();

        $this->expectException(LamboException::class);

        app(VerifyPathAvailable::class)();
    }

    /** @test */
    function it_ignores_a_pre_existing_directory_if_the_force_option_is_specified()
    {
        config(['lambo.store.root_path' => '/some/filesystem/path']);
        config(['lambo.store.project_path' => '/some/filesystem/path/existing-directory']);
        config(['lambo.store.force_create' => true]);

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path')
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path/existing-directory')
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();

        File::shouldReceive('deleteDirectory')
            ->with('/some/filesystem/path/existing-directory')
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();

        app(VerifyPathAvailable::class)();
    }

    /** @test */
    public function it_throws_a_lambo_exception_if_it_fails_to_delete_the_pre_existing_directory()
    {
        config(['lambo.store.root_path' => '/some/filesystem/path']);
        config(['lambo.store.project_path' => '/some/filesystem/path/existing-directory']);
        config(['lambo.store.force_create' => true]);

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path')
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path/existing-directory')
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();

        File::shouldReceive('deleteDirectory')
            ->with('/some/filesystem/path/existing-directory')
            ->once()
            ->andReturn(false)
            ->globally()
            ->ordered();

        $this->expectException(LamboException::class);

        app(VerifyPathAvailable::class)();
    }


    /** @test */
    function it_throws_an_exception_if_project_path_is_empty()
    {
        config(['lambo.store.root_path' => '/some/filesystem/path']);
        config(['lambo.store.project_path' => '']);

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path')
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();

        $this->expectException(Exception::class);

        app(VerifyPathAvailable::class)();
    }

    /** @test */
    function it_throws_an_exception_if_project_path_is_null()
    {
        config(['lambo.store.root_path' => '/some/filesystem/path']);
        config(['lambo.store.project_path' => null]);

        File::shouldReceive('isDirectory')
            ->with('/some/filesystem/path')
            ->once()
            ->andReturn(true)
            ->globally()
            ->ordered();

        $this->expectException(Exception::class);

        app(VerifyPathAvailable::class)();
    }
}


================================================
FILE: tests/TestCase.php
================================================
<?php

namespace Tests;

use App\ConsoleWriter;
use App\Shell;
use LaravelZero\Framework\Testing\TestCase as BaseTestCase;
use Tests\Feature\Fakes\FakeProcess;

abstract class TestCase extends BaseTestCase
{
    use CreatesApplication;

    protected $shell;

    function setUp(): void
    {
        parent::setUp();

        $this->mockConsoleWriter();

        $this->shell = $this->mock(Shell::class);
    }

    protected function mockConsoleWriter(): void
    {
        $consoleWriter = $this->mock(ConsoleWriter::class, function ($consoleWriter) {
            $consoleWriter->shouldReceive('logStep');
            $consoleWriter->shouldReceive('title');
     
Download .txt
gitextract_7pldj4rw/

├── .editorconfig
├── .gitattributes
├── .github/
│   └── workflows/
│       └── run-tests.yml
├── .gitignore
├── .phpcs.xml.dist
├── LICENSE.TXT
├── app/
│   ├── Actions/
│   │   ├── AbortsCommands.php
│   │   ├── Concerns/
│   │   │   ├── InteractsWithComposer.php
│   │   │   ├── InteractsWithGitHub.php
│   │   │   └── InteractsWithNpm.php
│   │   ├── CreateDatabase.php
│   │   ├── CustomizeDotEnv.php
│   │   ├── DisplayHelpScreen.php
│   │   ├── DisplayLamboWelcome.php
│   │   ├── EditConfigFile.php
│   │   ├── GenerateAppKey.php
│   │   ├── InitializeGitHubRepository.php
│   │   ├── InitializeGitRepository.php
│   │   ├── InstallBreeze.php
│   │   ├── InstallJetstream.php
│   │   ├── InstallLaravel.php
│   │   ├── InstallNpmDependencies.php
│   │   ├── MigrateDatabase.php
│   │   ├── OpenInBrowser.php
│   │   ├── OpenInEditor.php
│   │   ├── PushToGitHub.php
│   │   ├── RunAfterScript.php
│   │   ├── UpgradeSavedConfiguration.php
│   │   ├── ValetLink.php
│   │   ├── ValetSecure.php
│   │   ├── ValidateGitHubConfiguration.php
│   │   ├── VerifyDependencies.php
│   │   └── VerifyPathAvailable.php
│   ├── Commands/
│   │   ├── .gitkeep
│   │   ├── Debug.php
│   │   ├── EditAfter.php
│   │   ├── EditConfig.php
│   │   ├── HelpCommand.php
│   │   ├── LamboCommand.php
│   │   └── NewCommand.php
│   ├── Configuration/
│   │   ├── CommandLineConfiguration.php
│   │   ├── LamboConfiguration.php
│   │   ├── SavedConfiguration.php
│   │   ├── SetConfig.php
│   │   └── ShellConfiguration.php
│   ├── ConsoleWriter.php
│   ├── Environment.php
│   ├── Helpers/
│   │   └── GetTimezone.php
│   ├── LamboException.php
│   ├── LogsToConsole.php
│   ├── Options.php
│   ├── Providers/
│   │   └── AppServiceProvider.php
│   ├── Shell.php
│   └── Tools/
│       └── Database.php
├── bin/
│   └── testLambo.sh
├── bootstrap/
│   └── app.php
├── box.json
├── builds/
│   └── lambo
├── composer.json
├── config/
│   ├── app.php
│   └── commands.php
├── lambo
├── phpunit.xml.dist
├── readme.md
├── stubs/
│   ├── after
│   └── config
├── tests/
│   ├── CreatesApplication.php
│   ├── Feature/
│   │   ├── CreateDatabaseTest.php
│   │   ├── CustomizeDotEnvTest.php
│   │   ├── EditConfigFileTest.php
│   │   ├── Fakes/
│   │   │   └── FakeProcess.php
│   │   ├── Fixtures/
│   │   │   ├── .lambo/
│   │   │   │   ├── commented_configuration
│   │   │   │   ├── config
│   │   │   │   └── old_configuration
│   │   │   ├── composer-with-laravel-jetstream.json
│   │   │   ├── composer-without-laravel-jetstream.json
│   │   │   ├── composer.json
│   │   │   ├── package-silent.json
│   │   │   └── package.json
│   │   ├── GenerateAppKeyTest.php
│   │   ├── InitializeGitHubRepositoryTest.php
│   │   ├── InitializeGitRepositoryTest.php
│   │   ├── InstallBreezeTest.php
│   │   ├── InstallJetstreamTest.php
│   │   ├── InstallLaravelTest.php
│   │   ├── InstallNpmDependenciesTest.php
│   │   ├── LamboTestEnvironment.php
│   │   ├── MigrateDatabaseTest.php
│   │   ├── OpenInBrowserTest.php
│   │   ├── OpenInEditorTest.php
│   │   ├── PushToGitHubTest.php
│   │   ├── RunAfterScriptTest.php
│   │   ├── SignatureBuilderTest.php
│   │   ├── UpgradeSavedConfigurationTest.php
│   │   ├── ValetLinkTest.php
│   │   ├── ValetSecureTest.php
│   │   ├── ValidateGitHubConfigurationTest.php
│   │   ├── VerifyDependenciesTest.php
│   │   └── VerifyPathAvailableTest.php
│   ├── TestCase.php
│   └── Unit/
│       ├── CommandLineConfigurationTest.php
│       ├── Fakes/
│       │   └── FakeInput.php
│       ├── GetTimezoneTest.php
│       ├── SavedConfigurationTest.php
│       ├── SetConfigTest.php
│       └── ShellConfigurationTest.php
└── tlint.json
Download .txt
SYMBOL INDEX (434 symbols across 79 files)

FILE: app/Actions/AbortsCommands.php
  type AbortsCommands (line 7) | trait AbortsCommands
    method abortIf (line 9) | public function abortIf(bool $abort, string $message, $process = null)

FILE: app/Actions/Concerns/InteractsWithComposer.php
  type InteractsWithComposer (line 8) | trait InteractsWithComposer
    method composerRequire (line 12) | protected function composerRequire(string $package, bool $forDev = tru...
    method getComposerRequireCommand (line 19) | protected function getComposerRequireCommand(string $package, bool $fo...

FILE: app/Actions/Concerns/InteractsWithGitHub.php
  type InteractsWithGitHub (line 8) | trait InteractsWithGitHub
    method shouldCreateRepository (line 10) | protected static function shouldCreateRepository(): bool
    method gitHubInitializationRequested (line 15) | protected static function gitHubInitializationRequested(): bool
    method getDescription (line 20) | protected static function getDescription(): string
    method getHomepage (line 31) | protected static function getHomepage(): string
    method getGitHubCreateCommand (line 45) | protected static function getGitHubCreateCommand(): string
    method getRepositoryName (line 70) | protected static function getRepositoryName(): string
    method ghInstalled (line 78) | protected static function ghInstalled(): bool
    method hubInstalled (line 83) | protected static function hubInstalled(): bool
    method gitHubToolingInstalled (line 88) | protected static function gitHubToolingInstalled(): bool

FILE: app/Actions/Concerns/InteractsWithNpm.php
  type InteractsWithNpm (line 8) | trait InteractsWithNpm
    method installAndCompileNodeDependencies (line 15) | protected function installAndCompileNodeDependencies(): void
    method installNodeDependencies (line 24) | public function installNodeDependencies(): void
    method compileNodeDependencies (line 33) | protected function compileNodeDependencies(): void

FILE: app/Actions/CreateDatabase.php
  class CreateDatabase (line 10) | class CreateDatabase
    method __construct (line 18) | public function __construct(Shell $shell, Database $database, ConsoleW...
    method __invoke (line 25) | public function __invoke()
    method failureToCreateError (line 53) | protected function failureToCreateError(string $db_name): string

FILE: app/Actions/CustomizeDotEnv.php
  class CustomizeDotEnv (line 9) | class CustomizeDotEnv
    method __construct (line 13) | public function __construct(ConsoleWriter $consoleWriter)
    method __invoke (line 18) | public function __invoke()
    method customize (line 32) | public function customize($contents): string
    method value (line 50) | public function value($key, $fallback)

FILE: app/Actions/DisplayHelpScreen.php
  class DisplayHelpScreen (line 7) | class DisplayHelpScreen
    method __invoke (line 9) | public function __invoke()
    method createCliStringForOptionDescriptions (line 15) | public function createCliStringForOptionDescriptions(): string
    method createCliStringForCommandUsage (line 30) | private function createCliStringForCommandUsage(): string

FILE: app/Actions/DisplayLamboWelcome.php
  class DisplayLamboWelcome (line 5) | class DisplayLamboWelcome
    method __construct (line 17) | public function __construct()
    method __invoke (line 22) | public function __invoke()

FILE: app/Actions/EditConfigFile.php
  class EditConfigFile (line 8) | class EditConfigFile
    method __construct (line 14) | public function __construct(Shell $shell)
    method __invoke (line 19) | public function __invoke(string $fileName)

FILE: app/Actions/GenerateAppKey.php
  class GenerateAppKey (line 8) | class GenerateAppKey
    method __construct (line 15) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 21) | public function __invoke()
    method withQuiet (line 32) | private function withQuiet()

FILE: app/Actions/InitializeGitHubRepository.php
  class InitializeGitHubRepository (line 9) | class InitializeGitHubRepository
    method __construct (line 19) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 25) | public function __invoke()

FILE: app/Actions/InitializeGitRepository.php
  class InitializeGitRepository (line 8) | class InitializeGitRepository
    method __construct (line 15) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 21) | public function __invoke()
    method exec (line 41) | public function exec($command)

FILE: app/Actions/InstallBreeze.php
  class InstallBreeze (line 11) | class InstallBreeze
    method __construct (line 26) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 32) | public function __invoke()
    method installBreeze (line 51) | protected function installBreeze($stack): void

FILE: app/Actions/InstallJetstream.php
  class InstallJetstream (line 11) | class InstallJetstream
    method __construct (line 34) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 43) | public function __invoke(): void
    method installJetstream (line 65) | protected function installJetstream(string $stack): void

FILE: app/Actions/InstallLaravel.php
  class InstallLaravel (line 8) | class InstallLaravel
    method __construct (line 15) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 21) | public function __invoke()

FILE: app/Actions/InstallNpmDependencies.php
  class InstallNpmDependencies (line 8) | class InstallNpmDependencies
    method __construct (line 15) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 21) | public function __invoke()
    method withQuiet (line 32) | public function withQuiet()

FILE: app/Actions/MigrateDatabase.php
  class MigrateDatabase (line 10) | class MigrateDatabase
    method __construct (line 18) | public function __construct(Shell $shell, Database $database, ConsoleW...
    method __invoke (line 25) | public function __invoke()
    method failureMigrateError (line 49) | protected function failureMigrateError(): string
    method withQuiet (line 59) | private function withQuiet()

FILE: app/Actions/OpenInBrowser.php
  class OpenInBrowser (line 8) | class OpenInBrowser
    method __construct (line 16) | public function __construct(Shell $shell, Environment $environment)
    method __invoke (line 22) | public function __invoke()
    method browser (line 43) | public function browser()

FILE: app/Actions/OpenInEditor.php
  class OpenInEditor (line 8) | class OpenInEditor
    method __construct (line 15) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 21) | public function __invoke()

FILE: app/Actions/PushToGitHub.php
  class PushToGitHub (line 8) | class PushToGitHub
    method __construct (line 16) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 22) | public function __invoke()

FILE: app/Actions/RunAfterScript.php
  class RunAfterScript (line 9) | class RunAfterScript
    method __construct (line 16) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 22) | public function __invoke()

FILE: app/Actions/UpgradeSavedConfiguration.php
  class UpgradeSavedConfiguration (line 9) | class UpgradeSavedConfiguration
    method __construct (line 58) | public function __construct()
    method __invoke (line 65) | public function __invoke(): bool
    method upgrade (line 82) | public function upgrade(string $savedConfiguration, array $removedConf...
    method shouldUpgrade (line 94) | private function shouldUpgrade(): bool
    method commentRemovedConfiguration (line 111) | private function commentRemovedConfiguration(string $savedConfiguratio...
    method summarizeComments (line 125) | private function summarizeComments(): string
    method addNewConfiguration (line 140) | private function addNewConfiguration(array $newConfiguration): string

FILE: app/Actions/ValetLink.php
  class ValetLink (line 8) | class ValetLink
    method __construct (line 16) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 22) | public function __invoke()

FILE: app/Actions/ValetSecure.php
  class ValetSecure (line 8) | class ValetSecure
    method __construct (line 15) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 21) | public function __invoke()

FILE: app/Actions/ValidateGitHubConfiguration.php
  class ValidateGitHubConfiguration (line 10) | class ValidateGitHubConfiguration
    method __construct (line 32) | public function __construct(Shell $shell, ConsoleWriter $consoleWriter)
    method __invoke (line 38) | public function __invoke()
    method askToContinueWithoutGitHubSetup (line 67) | private function askToContinueWithoutGitHubSetup()
    method ghAuthenticated (line 76) | private function ghAuthenticated(): bool

FILE: app/Actions/VerifyDependencies.php
  class VerifyDependencies (line 8) | class VerifyDependencies
    method __construct (line 46) | public function __construct(ExecutableFinder $finder, ConsoleWriter $c...
    method __invoke (line 52) | public function __invoke()

FILE: app/Actions/VerifyPathAvailable.php
  class VerifyPathAvailable (line 8) | class VerifyPathAvailable
    method __invoke (line 14) | public function __invoke()

FILE: app/Commands/Debug.php
  type Debug (line 12) | trait Debug
    method arrayToTable (line 14) | protected function arrayToTable(array $data, array $filter = null, str...
    method debugReport (line 53) | protected function debugReport(): void
    method configToTable (line 150) | protected function configToTable(): void
    method dotFlatten (line 156) | private function dotFlatten($prefix, $array): array
    method logTimezoneData (line 169) | protected function logTimezoneData()

FILE: app/Commands/EditAfter.php
  class EditAfter (line 13) | class EditAfter extends LamboCommand
    method handle (line 19) | public function handle()

FILE: app/Commands/EditConfig.php
  class EditConfig (line 13) | class EditConfig extends LamboCommand
    method handle (line 19) | public function handle()

FILE: app/Commands/HelpCommand.php
  class HelpCommand (line 8) | class HelpCommand extends LamboCommand
    method handle (line 13) | public function handle()

FILE: app/Commands/LamboCommand.php
  class LamboCommand (line 10) | abstract class LamboCommand extends Command
    method run (line 12) | public function run(InputInterface $input, OutputInterface $output): int

FILE: app/Commands/NewCommand.php
  class NewCommand (line 36) | class NewCommand extends LamboCommand
    method __construct (line 44) | public function __construct()
    method buildSignature (line 55) | public function buildSignature()
    method buildSignatureOption (line 65) | public function buildSignatureOption($option): string
    method handle (line 76) | public function handle()
    method setConsoleWriter (line 132) | protected function setConsoleWriter()
    method setConfig (line 137) | private function setConfig(): void

FILE: app/Configuration/CommandLineConfiguration.php
  class CommandLineConfiguration (line 5) | class CommandLineConfiguration extends LamboConfiguration
    method getSettings (line 7) | protected function getSettings(): array

FILE: app/Configuration/LamboConfiguration.php
  class LamboConfiguration (line 7) | abstract class LamboConfiguration
    method __construct (line 39) | public function __construct(array $keyMap)
    method getSettings (line 48) | abstract protected function getSettings(): array;
    method get (line 50) | protected function get(string $key, array $array)
    method __get (line 71) | public function __get($name)

FILE: app/Configuration/SavedConfiguration.php
  class SavedConfiguration (line 8) | class SavedConfiguration extends LamboConfiguration
    method getSettings (line 10) | protected function getSettings(): array

FILE: app/Configuration/SetConfig.php
  class SetConfig (line 17) | class SetConfig
    method __construct (line 35) | public function __construct(
    method __invoke (line 52) | public function __invoke($defaultConfiguration)
    method get (line 78) | private function get(string $configurationKey, $default)
    method getTld (line 95) | private function getTld(): string
    method getRootPath (line 118) | private function getRootPath(string $key, $default)
    method getDatabaseName (line 127) | private function getDatabaseName(string $key, $default)
    method getProjectURL (line 132) | private function getProjectURL(): string
    method getMigrateDatabase (line 142) | private function getMigrateDatabase(string $key, $default)
    method getWithOutput (line 151) | private function getWithOutput(string $key, $default): bool
    method getBreeze (line 160) | private function getBreeze(string $key, $default)
    method getJetstream (line 175) | private function getJetstream(string $key, $default)
    method configureBreezeStack (line 190) | private function configureBreezeStack(): string
    method configureJetstreamStack (line 199) | private function configureJetstreamStack(): string
    method ensureOnlyOneStarterKitSelected (line 209) | private function ensureOnlyOneStarterKitSelected(): void

FILE: app/Configuration/ShellConfiguration.php
  class ShellConfiguration (line 5) | class ShellConfiguration extends LamboConfiguration
    method getSettings (line 7) | protected function getSettings(): array

FILE: app/ConsoleWriter.php
  class ConsoleWriter (line 8) | class ConsoleWriter extends OutputStyle
    method formatString (line 15) | public static function formatString(string $string, string $format): s...
    method panel (line 20) | public function panel(string $prefix, string $message, string $style)
    method sectionTitle (line 25) | public function sectionTitle($sectionTitle)
    method logStep (line 34) | public function logStep($message)
    method exec (line 39) | public function exec(string $command)
    method success (line 44) | public function success($message, $label = 'PASS'): void
    method ok (line 49) | public function ok($message): void
    method note (line 54) | public function note($message, $label = 'NOTE'): void
    method warn (line 59) | public function warn($message, $label = 'WARN'): void
    method warnCommandFailed (line 64) | public function warnCommandFailed($command): void
    method showOutputErrors (line 69) | public function showOutputErrors(string $errors)
    method showOutput (line 78) | public function showOutput(string $errors)
    method exception (line 87) | public function exception($message)
    method text (line 92) | public function text($message)
    method listing (line 97) | public function listing(array $items): void
    method table (line 107) | public function table(array $columnHeadings, array $rowData)
    method consoleOutput (line 112) | public function consoleOutput(string $line, $type)
    method labeledLine (line 121) | public function labeledLine(string $label, string $message, string $la...

FILE: app/Environment.php
  class Environment (line 5) | class Environment
    method isMac (line 7) | public static function isMac(): bool

FILE: app/Helpers/GetTimezone.php
  class GetTimezone (line 7) | class GetTimezone
    method __invoke (line 9) | public function __invoke(): string

FILE: app/LamboException.php
  class LamboException (line 7) | class LamboException extends Exception

FILE: app/LogsToConsole.php
  type LogsToConsole (line 5) | trait LogsToConsole
    method alert (line 7) | public function alert(string $message)
    method warn (line 12) | public function warn(string $message)
    method error (line 17) | public function error(string $message)
    method line (line 22) | public function line(string $message)
    method info (line 27) | public function info(string $message)

FILE: app/Options.php
  class Options (line 5) | class Options
    method all (line 131) | public function all(): array

FILE: app/Providers/AppServiceProvider.php
  class AppServiceProvider (line 7) | class AppServiceProvider extends ServiceProvider
    method boot (line 14) | public function boot()
    method register (line 34) | public function register()

FILE: app/Shell.php
  class Shell (line 8) | class Shell
    method __construct (line 16) | public function __construct(Repository $config, ConsoleWriter $console...
    method execInRoot (line 23) | public function execInRoot($command)
    method execInProject (line 28) | public function execInProject($command)
    method execIn (line 33) | public function execIn(string $directory, string $command)
    method exec (line 38) | public function exec(string $command)
    method execQuietly (line 60) | public function execQuietly(string $command)
    method withTTY (line 71) | public function withTTY()

FILE: app/Tools/Database.php
  class Database (line 7) | class Database
    method fill (line 13) | public function fill(string $type, string $host, $port, string $userna...
    method fillFromUrl (line 22) | public function fillFromUrl(string $url): self
    method fillFromLamboStore (line 29) | public function fillFromLamboStore(array $store): self
    method ensureExists (line 40) | public function ensureExists(string $databaseName = null)
    method create (line 49) | public function create(string $databaseName)

FILE: tests/CreatesApplication.php
  type CreatesApplication (line 7) | trait CreatesApplication
    method createApplication (line 14) | public function createApplication()

FILE: tests/Feature/CreateDatabaseTest.php
  class CreateDatabaseTest (line 9) | class CreateDatabaseTest extends TestCase
    method setUp (line 13) | public function setUp(): void
    method it_creates_a_mysql_database (line 21) | function it_creates_a_mysql_database()
    method it_skips_database_creation (line 49) | function it_skips_database_creation()

FILE: tests/Feature/CustomizeDotEnvTest.php
  class CustomizeDotEnvTest (line 9) | class CustomizeDotEnvTest extends TestCase
    method it_saves_the_customized_dot_env_files (line 12) | function it_saves_the_customized_dot_env_files()
    method it_replaces_static_strings (line 38) | function it_replaces_static_strings()
    method un_targeted_lines_are_unchanged (line 49) | function un_targeted_lines_are_unchanged()
    method lines_with_no_equals_are_unchanged (line 60) | function lines_with_no_equals_are_unchanged()
    method line_breaks_remain (line 69) | function line_breaks_remain()

FILE: tests/Feature/EditConfigFileTest.php
  class EditConfigFileTest (line 11) | class EditConfigFileTest extends TestCase
    method setUp (line 17) | public function setUp(): void
    method it_creates_the_config_directory_and_file_then_opens_the_file_for_editing (line 33) | function it_creates_the_config_directory_and_file_then_opens_the_file_...
    method it_creates_a_config_file_then_opens_the_file_for_editing (line 49) | function it_creates_a_config_file_then_opens_the_file_for_editing()
    method it_opens_a_config_file_for_editing (line 60) | function it_opens_a_config_file_for_editing()
    method it_throws_an_exception_if_the_configured_editor_fails_to_open (line 70) | function it_throws_an_exception_if_the_configured_editor_fails_to_open()
    method failing_to_create_the_configuration_directory_throws_an_exception (line 82) | function failing_to_create_the_configuration_directory_throws_an_excep...
    method failing_to_create_the_configuration_file_throws_an_exception (line 93) | public function failing_to_create_the_configuration_file_throws_an_exc...
    method configDirectoryExists (line 104) | private function configDirectoryExists(bool $exists = true): void
    method successfullyCreateConfigDirectory (line 114) | private function successfullyCreateConfigDirectory(bool $success = tru...
    method configFileExists (line 124) | private function configFileExists(bool $success = true): void
    method successfullyCreateConfigFile (line 134) | private function successfullyCreateConfigFile(bool $success = true): void
    method successfullyOpenInEditor (line 150) | private function successfullyOpenInEditor(bool $success = true)
    method the_config_directory_does_not_exist (line 172) | private function the_config_directory_does_not_exist()
    method the_config_directory_is_created (line 182) | private function the_config_directory_is_created()
    method the_config_file_does_not_exist (line 192) | private function the_config_file_does_not_exist()
    method the_config_file_is_created (line 202) | private function the_config_file_is_created()
    method the_config_file_is_opened_for_editing (line 218) | private function the_config_file_is_opened_for_editing()

FILE: tests/Feature/Fakes/FakeProcess.php
  class FakeProcess (line 5) | class FakeProcess
    method __construct (line 13) | public function __construct(bool $isSuccessful, string $failedCommand ...
    method success (line 19) | public static function success(): FakeProcess
    method fail (line 24) | public static function fail(string $failedCommand): FakeProcess
    method isSuccessful (line 29) | public function isSuccessful(): bool
    method getCommandLine (line 34) | public function getCommandLine(): string
    method withOutput (line 39) | public function withOutput(string $output): FakeProcess
    method withErrorOutput (line 45) | public function withErrorOutput(string $errorOutput): FakeProcess
    method getOutput (line 51) | public function getOutput()
    method getErrorOutput (line 56) | public function getErrorOutput()
    method getExitCode (line 61) | public function getExitCode()

FILE: tests/Feature/GenerateAppKeyTest.php
  class GenerateAppKeyTest (line 10) | class GenerateAppKeyTest extends TestCase
    method it_generates_a_new_app_key (line 13) | function it_generates_a_new_app_key()
    method it_throws_an_exception_if_new_app_key_generation_fails (line 24) | function it_throws_an_exception_if_new_app_key_generation_fails()

FILE: tests/Feature/InitializeGitHubRepositoryTest.php
  class InitializeGitHubRepositoryTest (line 16) | class InitializeGitHubRepositoryTest extends TestCase
    method it_manages_new_repository_initialization (line 127) | function it_manages_new_repository_initialization()
    method it_warns_the_user_if_repository_creation_fails (line 158) | function it_warns_the_user_if_repository_creation_fails()

FILE: tests/Feature/InitializeGitRepositoryTest.php
  class InitializeGitRepositoryTest (line 10) | class InitializeGitRepositoryTest extends TestCase
    method it_initializes_git (line 13) | function it_initializes_git()
    method it_throws_an_exception_if_git_init_fails (line 36) | function it_throws_an_exception_if_git_init_fails()
    method it_throws_an_exception_if_git_add_fails (line 49) | function it_throws_an_exception_if_git_add_fails()
    method it_throws_an_exception_if_git_commit_fails (line 67) | function it_throws_an_exception_if_git_commit_fails()
    method it_removes_the_quiet_flag_when_show_output_is_enabled (line 93) | function it_removes_the_quiet_flag_when_show_output_is_enabled()

FILE: tests/Feature/InstallBreezeTest.php
  class InstallBreezeTest (line 13) | class InstallBreezeTest extends TestCase
    method it_installs_laravel_breeze (line 19) | function it_installs_laravel_breeze()
    method it_skips_breeze_installation (line 48) | function it_skips_breeze_installation()
    method it_throws_a_lambo_exception_if_an_invalid_breeze_stack_is_requested (line 59) | function it_throws_a_lambo_exception_if_an_invalid_breeze_stack_is_req...
    method it_throws_a_lambo_exception_if_composer_installation_fails (line 79) | function it_throws_a_lambo_exception_if_composer_installation_fails()
    method it_throws_a_lambo_exception_if_breeze_installation_fails (line 90) | function it_throws_a_lambo_exception_if_breeze_installation_fails()
    method getComposerCommand (line 102) | private function getComposerCommand(bool $withOutput = false): string
    method getBreezeInstallCommand (line 107) | private function getBreezeInstallCommand(string $stack, $showOutput): ...
    method getNpmInstallCommand (line 116) | private function getNpmInstallCommand($showOutput): string
    method getCompileAssetsCommand (line 121) | private function getCompileAssetsCommand($withOutput): string
    method logUseCase (line 126) | private function logUseCase(string $stack, $showOutput): void

FILE: tests/Feature/InstallJetstreamTest.php
  class InstallJetstreamTest (line 13) | class InstallJetstreamTest extends TestCase
    method it_installs_laravel_jetstream (line 19) | function it_installs_laravel_jetstream()
    method it_skips_jetstream_installation (line 50) | function it_skips_jetstream_installation()
    method it_throws_a_lambo_exception_if_an_invalid_jetstream_stack_is_requested (line 61) | function it_throws_a_lambo_exception_if_an_invalid_jetstream_stack_is_...
    method it_throws_a_lambo_exception_if_composer_installation_fails (line 81) | function it_throws_a_lambo_exception_if_composer_installation_fails()
    method it_throws_a_lambo_exception_if_jetstream_installation_fails (line 92) | function it_throws_a_lambo_exception_if_jetstream_installation_fails()
    method getJetstreamInstallCommand (line 103) | private function getJetstreamInstallCommand(string $stack, $showOutput...
    method getNpmInstallCommand (line 108) | private function getNpmInstallCommand($showOutput): string
    method getComposerCommand (line 113) | private function getComposerCommand(bool $withOutput = false): string
    method getCompileAssetsCommand (line 118) | private function getCompileAssetsCommand($withOutput): string
    method logUseCase (line 123) | private function logUseCase(string $stack, $useTeams, $showOutput): void

FILE: tests/Feature/InstallLaravelTest.php
  class InstallLaravelTest (line 10) | class InstallLaravelTest extends TestCase
    method it_installs_laravel (line 13) | function it_installs_laravel()
    method it_throws_an_exception_if_laravel_fails_to_install (line 39) | function it_throws_an_exception_if_laravel_fails_to_install()

FILE: tests/Feature/InstallNpmDependenciesTest.php
  class InstallNpmDependenciesTest (line 10) | class InstallNpmDependenciesTest extends TestCase
    method it_installs_npm_dependencies (line 13) | function it_installs_npm_dependencies()
    method it_installs_npm_dependencies_and_shows_console_output (line 26) | function it_installs_npm_dependencies_and_shows_console_output()
    method it_throws_an_exception_if_npm_install_fails (line 39) | function it_throws_an_exception_if_npm_install_fails()

FILE: tests/Feature/LamboTestEnvironment.php
  type LamboTestEnvironment (line 7) | trait LamboTestEnvironment
    method withValetTld (line 9) | protected function withValetTld($tld = 'test'): void

FILE: tests/Feature/MigrateDatabaseTest.php
  class MigrateDatabaseTest (line 11) | class MigrateDatabaseTest extends TestCase
    method setUp (line 15) | public function setUp(): void
    method it_migrates_the_database (line 22) | function it_migrates_the_database()
    method failed_migrations_do_not_halt_execution (line 53) | function failed_migrations_do_not_halt_execution()
    method it_skips_migrations (line 84) | function it_skips_migrations()

FILE: tests/Feature/OpenInBrowserTest.php
  class OpenInBrowserTest (line 10) | class OpenInBrowserTest extends TestCase
    method setUp (line 14) | public function setUp(): void
    method it_uses_the_open_command_on_mac_when_a_browser_is_specified (line 21) | function it_uses_the_open_command_on_mac_when_a_browser_is_specified()
    method it_uses_valet_open_on_mac_when_no_browser_is_specified (line 38) | function it_uses_valet_open_on_mac_when_no_browser_is_specified()
    method it_uses_valet_open_when_not_running_on_mac (line 54) | function it_uses_valet_open_when_not_running_on_mac()
    method it_ignores_the_specified_browser_when_not_running_on_mac (line 68) | function it_ignores_the_specified_browser_when_not_running_on_mac()
    method it_skips_opening_the_site (line 85) | function it_skips_opening_the_site()

FILE: tests/Feature/OpenInEditorTest.php
  class OpenInEditorTest (line 10) | class OpenInEditorTest extends TestCase
    method it_opens_the_project_folder_in_the_specified_editor (line 13) | function it_opens_the_project_folder_in_the_specified_editor()
    method it_throws_an_exception_if_it_fails_to_open_the_editor (line 30) | function it_throws_an_exception_if_it_fails_to_open_the_editor()

FILE: tests/Feature/PushToGitHubTest.php
  class PushToGitHubTest (line 14) | class PushToGitHubTest extends TestCase
    method it_pushes_to_github (line 19) | function it_pushes_to_github()
    method it_logs_a_warning_if_branch_name_cannot_be_determined (line 39) | function it_logs_a_warning_if_branch_name_cannot_be_determined()
    method it_logs_a_warning_if_pushing_to_git_hub_fails (line 67) | function it_logs_a_warning_if_pushing_to_git_hub_fails()
    method it_skips_pushing_to_github (line 103) | function it_skips_pushing_to_github()
    method shouldLogWarning (line 118) | private function shouldLogWarning(string $warning): void
    method shouldLogStep (line 126) | private function shouldLogStep(string $step)
    method shouldShowOutputErrors (line 134) | private function shouldShowOutputErrors(string $error)

FILE: tests/Feature/RunAfterScriptTest.php
  class RunAfterScriptTest (line 11) | class RunAfterScriptTest extends TestCase
    method setUp (line 13) | function setUp(): void
    method it_runs_the_after_script_if_one_exists (line 21) | function it_runs_the_after_script_if_one_exists()
    method it_throws_an_exception_if_the_after_script_fails (line 45) | function it_throws_an_exception_if_the_after_script_fails()
    method getAfterScriptPath (line 70) | private function getAfterScriptPath(): string
    method getHomeDirectory (line 75) | private function getHomeDirectory(): string
    method getCommand (line 80) | private function getCommand(): string
    method getProjectPath (line 85) | private function getProjectPath(): string

FILE: tests/Feature/SignatureBuilderTest.php
  class SignatureBuilderTest (line 8) | class SignatureBuilderTest extends TestCase
    method it_offers_short_and_long_codes (line 11) | function it_offers_short_and_long_codes()
    method it_functions_given_only_long_code (line 24) | function it_functions_given_only_long_code()
    method it_sets_expectation_for_values_if_option_expects_parameters (line 36) | function it_sets_expectation_for_values_if_option_expects_parameters()
    method it_does_not_set_expectation_for_values_if_option_does_not_expect_parameters (line 49) | function it_does_not_set_expectation_for_values_if_option_does_not_exp...
    method it_defines_description (line 61) | function it_defines_description()

FILE: tests/Feature/UpgradeSavedConfigurationTest.php
  class UpgradeSavedConfigurationTest (line 9) | class UpgradeSavedConfigurationTest extends TestCase
    method it_upgrades_saved_configuration (line 41) | function it_upgrades_saved_configuration()
    method getConfiguration (line 81) | private function getConfiguration(): string

FILE: tests/Feature/ValetLinkTest.php
  class ValetLinkTest (line 10) | class ValetLinkTest extends TestCase
    method it_runs_valet_link (line 13) | function it_runs_valet_link()
    method it_throws_an_exception_if_valet_link_fails (line 26) | function it_throws_an_exception_if_valet_link_fails()

FILE: tests/Feature/ValetSecureTest.php
  class ValetSecureTest (line 10) | class ValetSecureTest extends TestCase
    method it_runs_valet_secure (line 13) | function it_runs_valet_secure()
    method it_throws_an_exception_if_valet_secure_fails (line 26) | function it_throws_an_exception_if_valet_secure_fails()

FILE: tests/Feature/ValidateGitHubConfigurationTest.php
  class ValidateGitHubConfigurationTest (line 15) | class ValidateGitHubConfigurationTest extends TestCase
    method it_skips_gh_command_line_tool_validation (line 21) | function it_skips_gh_command_line_tool_validation()
    method it_logs_a_warning_if_github_tooling_is_missing (line 36) | function it_logs_a_warning_if_github_tooling_is_missing()
    method configuration_is_valid_if_hub_is_installed (line 55) | function configuration_is_valid_if_hub_is_installed()
    method configuration_is_valid_if_gh_is_installed_and_authenticated (line 71) | function configuration_is_valid_if_gh_is_installed_and_authenticated()
    method it_logs_a_warning_if_gh_is_not_authenticated_with_github (line 91) | function it_logs_a_warning_if_gh_is_not_authenticated_with_github()
    method shouldLogChosenGitHubTool (line 113) | private function shouldLogChosenGitHubTool(string $tool): void
    method shouldLogWarning (line 121) | private function shouldLogWarning(): void
    method shouldAskToContinue (line 129) | private function shouldAskToContinue(): void
    method shouldLogInstructions (line 139) | private function shouldLogInstructions(array $instructions): void

FILE: tests/Feature/VerifyDependenciesTest.php
  class VerifyDependenciesTest (line 10) | class VerifyDependenciesTest extends TestCase
    method setUp (line 14) | public function setUp(): void
    method it_checks_that_dependencies_are_available (line 21) | function it_checks_that_dependencies_are_available()
    method it_marks_optional_dependencies_as_missing (line 33) | function it_marks_optional_dependencies_as_missing()
    method it_throws_a_lambo_exception_if_composer_is_missing (line 48) | function it_throws_a_lambo_exception_if_composer_is_missing()
    method it_throws_a_lambo_exception_if_valet_is_missing (line 62) | function it_throws_a_lambo_exception_if_valet_is_missing()
    method it_throws_a_lambo_exception_if_git_is_missing (line 76) | function it_throws_a_lambo_exception_if_git_is_missing()
    method dependencyIsAvailable (line 89) | private function dependencyIsAvailable(string $dependency, $isAvailabl...
    method dependencyIsMissing (line 100) | private function dependencyIsMissing(string $dependency)

FILE: tests/Feature/VerifyPathAvailableTest.php
  class VerifyPathAvailableTest (line 11) | class VerifyPathAvailableTest extends TestCase
    method it_checks_if_the_required_directories_are_available (line 14) | function it_checks_if_the_required_directories_are_available()
    method it_throws_a_lambo_exception_if_the_root_path_is_not_available (line 33) | function it_throws_a_lambo_exception_if_the_root_path_is_not_available()
    method it_throws_a_lambo_exception_if_the_project_path_already_exists (line 48) | function it_throws_a_lambo_exception_if_the_project_path_already_exists()
    method it_ignores_a_pre_existing_directory_if_the_force_option_is_specified (line 73) | function it_ignores_a_pre_existing_directory_if_the_force_option_is_sp...
    method it_throws_a_lambo_exception_if_it_fails_to_delete_the_pre_existing_directory (line 104) | public function it_throws_a_lambo_exception_if_it_fails_to_delete_the_...
    method it_throws_an_exception_if_project_path_is_empty (line 138) | function it_throws_an_exception_if_project_path_is_empty()
    method it_throws_an_exception_if_project_path_is_null (line 156) | function it_throws_an_exception_if_project_path_is_null()

FILE: tests/TestCase.php
  class TestCase (line 10) | abstract class TestCase extends BaseTestCase
    method setUp (line 16) | function setUp(): void
    method mockConsoleWriter (line 25) | protected function mockConsoleWriter(): void
    method todo (line 42) | protected function todo(array $lines)
    method toSTDOUT (line 47) | protected function toSTDOUT($out, string $title = null): void
    method shouldExecInProject (line 53) | protected function shouldExecInProject(string $command, bool $success ...
    method shouldExecInProjectAndFail (line 66) | protected function shouldExecInProjectAndFail(string $command)
    method isVerbose (line 71) | protected function isVerbose(): bool
    method isDebug (line 76) | protected function isDebug(): bool

FILE: tests/Unit/CommandLineConfigurationTest.php
  class CommandLineConfigurationTest (line 10) | class CommandLineConfigurationTest extends TestCase
    method setUp (line 14) | public function setUp(): void
    method it_gets_a_command_line_configuration_value (line 22) | function it_gets_a_command_line_configuration_value()
    method it_returns_null_if_a_command_line_configuration_value_is_missing (line 39) | function it_returns_null_if_a_command_line_configuration_value_is_miss...
    method it_returns_null_if_a_command_line_configuration_value_is_empty (line 54) | function it_returns_null_if_a_command_line_configuration_value_is_empty()
    method it_returns_null_if_a_non_existent_property_is_requested (line 71) | function it_returns_null_if_a_non_existent_property_is_requested()
    method withoutEnvironmentVariable (line 82) | protected function withoutEnvironmentVariable(array $keys): void
    method withoutCommandLineOptions (line 87) | protected function withoutCommandLineOptions(): void
    method withCommandLineOptions (line 92) | protected function withCommandLineOptions(array $commandLineOptions): ...
    method withCommandLineArgument (line 98) | protected function withCommandLineArgument(string $key, string $value)...
    method withoutCommandLineArguments (line 105) | private function withoutCommandLineArguments()

FILE: tests/Unit/Fakes/FakeInput.php
  class FakeInput (line 10) | class FakeInput implements InputInterface
    method __construct (line 15) | public function __construct(array $input = [])
    method getFirstArgument (line 23) | public function getFirstArgument(): null|string
    method hasParameterOption (line 28) | public function hasParameterOption(array|string $values, bool $onlyPar...
    method getParameterOption (line 33) | public function getParameterOption($values, $default = false, bool $on...
    method bind (line 38) | public function bind(InputDefinition $definition)
    method validate (line 43) | public function validate()
    method getArguments (line 48) | public function getArguments(): array
    method getArgument (line 53) | public function getArgument(string $name)
    method setArgument (line 58) | public function setArgument(string $name, $value)
    method hasArgument (line 63) | public function hasArgument(string $name): bool
    method getOptions (line 68) | public function getOptions(): array
    method getOption (line 73) | public function getOption(string $name)
    method setOption (line 78) | public function setOption(string $name, $value)
    method hasOption (line 83) | public function hasOption(string $name): bool
    method isInteractive (line 88) | public function isInteractive(): bool
    method setInteractive (line 93) | public function setInteractive(bool $interactive)

FILE: tests/Unit/GetTimezoneTest.php
  class GetTimezoneTest (line 9) | class GetTimezoneTest extends TestCase
    method it_uses_the_timezone_configured_in_php_ini (line 12) | function it_uses_the_timezone_configured_in_php_ini()

FILE: tests/Unit/SavedConfigurationTest.php
  class SavedConfigurationTest (line 8) | class SavedConfigurationTest extends TestCase
    method setUp (line 10) | public function setUp(): void
    method it_gets_a_saved_configuration_value (line 19) | function it_gets_a_saved_configuration_value()
    method it_returns_null_if_a_saved_configuration_option_is_missing (line 29) | function it_returns_null_if_a_saved_configuration_option_is_missing()
    method it_returns_null_if_a_saved_configuration_option_has_no_value (line 39) | function it_returns_null_if_a_saved_configuration_option_has_no_value()
    method it_returns_null_if_a_saved_configuration_option_is_empty (line 49) | function it_returns_null_if_a_saved_configuration_option_is_empty()
    method it_returns_null_when_the_configuration_file_does_not_exist (line 59) | function it_returns_null_when_the_configuration_file_does_not_exist()
    method it_returns_null_if_a_non_existent_property_is_requested (line 71) | function it_returns_null_if_a_non_existent_property_is_requested()
    method it_casts_strings_to_booleans (line 78) | function it_casts_strings_to_booleans()

FILE: tests/Unit/SetConfigTest.php
  class SetConfigTest (line 22) | class SetConfigTest extends TestCase
    method it_sets_the_top_level_domain (line 27) | function it_sets_the_top_level_domain()
    method it_sets_the_top_level_domain_using_legacy_valet_config (line 55) | function it_sets_the_top_level_domain_using_legacy_valet_config()
    method it_throws_a_LamboException_if_valet_config_is_missing (line 90) | function it_throws_a_LamboException_if_valet_config_is_missing()
    method it_prioritises_command_line_configuration (line 118) | function it_prioritises_command_line_configuration()
    method it_prioritises_saved_configuration_over_shell_environment_configuration (line 145) | function it_prioritises_saved_configuration_over_shell_environment_con...
    method it_prioritises_shell_environment_over_default_configuration (line 172) | function it_prioritises_shell_environment_over_default_configuration()
    method it_uses_a_default_configuration (line 199) | function it_uses_a_default_configuration()
    method it_replaces_tilda_in_root_path (line 226) | function it_replaces_tilda_in_root_path()
    method it_replaces_hyphens_with_underscores_in_database_names (line 262) | function it_replaces_hyphens_with_underscores_in_database_names()
    method it_sets_the_project_url (line 287) | function it_sets_the_project_url()
    method it_sets_the_project_name (line 332) | function it_sets_the_project_name()
    method it_sets_the_project_path (line 351) | function it_sets_the_project_path()
    method it_sets_the_create_database_configuration (line 376) | function it_sets_the_create_database_configuration()
    method it_sets_the_migrate_database_configuration (line 434) | function it_sets_the_migrate_database_configuration()
    method it_sets_the_valet_link_configuration (line 546) | function it_sets_the_valet_link_configuration()
    method it_sets_the_valet_secure_configuration (line 603) | function it_sets_the_valet_secure_configuration()
    method it_sets_the_breeze_starter_kit_configuration (line 663) | function it_sets_the_breeze_starter_kit_configuration()
    method it_sets_the_jetstream_starter_kit_configuration (line 699) | function it_sets_the_jetstream_starter_kit_configuration()
    method it_ensures_only_one_starter_kit_is_configured (line 735) | function it_ensures_only_one_starter_kit_is_configured()
    method it_asks_for_clarification_when_breeze_configuration_is_invalid (line 800) | function it_asks_for_clarification_when_breeze_configuration_is_invalid()
    method it_asks_for_clarification_when_jetstream_configuration_is_invalid (line 847) | function it_asks_for_clarification_when_jetstream_configuration_is_inv...

FILE: tests/Unit/ShellConfigurationTest.php
  class ShellConfigurationTest (line 9) | class ShellConfigurationTest extends TestCase
    method it_gets_the_value_of_of_a_shell_environment_variable (line 12) | function it_gets_the_value_of_of_a_shell_environment_variable()
    method it_returns_null_if_a_shell_environment_variable_is_missing (line 24) | function it_returns_null_if_a_shell_environment_variable_is_missing()
    method it_returns_null_if_a_shell_environment_variable_is_empty (line 36) | function it_returns_null_if_a_shell_environment_variable_is_empty()
    method it_returns_null_if_a_non_existent_property_is_requested (line 48) | function it_returns_null_if_a_non_existent_property_is_requested()
Condensed preview — 107 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (247K chars).
[
  {
    "path": ".editorconfig",
    "chars": 234,
    "preview": "root = true\n\n[*]\ncharset = utf-8\nend_of_line = lf\ninsert_final_newline = true\nindent_style = space\nindent_size = 4\ntrim_"
  },
  {
    "path": ".gitattributes",
    "chars": 38,
    "preview": "* text=auto\n.travis.yml export-ignore\n"
  },
  {
    "path": ".github/workflows/run-tests.yml",
    "chars": 913,
    "preview": "name: Run Tests\n\non:\n  push:\n    branches: [ main ]\n  pull_request:\n\njobs:\n  tests:\n    strategy:\n      matrix:\n        "
  },
  {
    "path": ".gitignore",
    "chars": 64,
    "preview": "/vendor\n.phpunit.result.cache\n/storage/framework/\n.php_cs.cache\n"
  },
  {
    "path": ".phpcs.xml.dist",
    "chars": 134,
    "preview": "<?xml version=\"1.0\"?>\n<ruleset>\n   <file>app</file>\n   <file>config</file>\n   <file>tests</file>\n\n   <rule ref=\"Tighten\""
  },
  {
    "path": "LICENSE.TXT",
    "chars": 1077,
    "preview": "The MIT License (MIT)\n\nCopyright (c) <Matt Stauffer>\n\nPermission is hereby granted, free of charge, to any person obtain"
  },
  {
    "path": "app/Actions/AbortsCommands.php",
    "chars": 398,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\LamboException;\n\ntrait AbortsCommands\n{\n    public function abortIf(bool $abort, "
  },
  {
    "path": "app/Actions/Concerns/InteractsWithComposer.php",
    "chars": 800,
    "preview": "<?php\n\nnamespace App\\Actions\\Concerns;\n\nuse App\\Actions\\AbortsCommands;\nuse App\\Shell;\n\ntrait InteractsWithComposer\n{\n  "
  },
  {
    "path": "app/Actions/Concerns/InteractsWithGitHub.php",
    "chars": 2611,
    "preview": "<?php\n\nnamespace App\\Actions\\Concerns;\n\nuse App\\Configuration\\LamboConfiguration;\nuse App\\LamboException;\n\ntrait Interac"
  },
  {
    "path": "app/Actions/Concerns/InteractsWithNpm.php",
    "chars": 1092,
    "preview": "<?php\n\nnamespace App\\Actions\\Concerns;\n\nuse App\\Actions\\AbortsCommands;\nuse App\\Shell;\n\ntrait InteractsWithNpm\n{\n    use"
  },
  {
    "path": "app/Actions/CreateDatabase.php",
    "chars": 1747,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\nuse App\\Tools\\Database;\nuse PDOException;\n\nclass Cr"
  },
  {
    "path": "app/Actions/CustomizeDotEnv.php",
    "chars": 1795,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse Illuminate\\Support\\Arr;\nuse Illuminate\\Support\\Facades\\File;\n\n"
  },
  {
    "path": "app/Actions/DisplayHelpScreen.php",
    "chars": 1766,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\Options;\n\nclass DisplayHelpScreen\n{\n    public function __invoke()\n    {\n        "
  },
  {
    "path": "app/Actions/DisplayLamboWelcome.php",
    "chars": 1057,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nclass DisplayLamboWelcome\n{\n    protected $lamboLogo = '\n     __                    __   "
  },
  {
    "path": "app/Actions/EditConfigFile.php",
    "chars": 1256,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\Shell;\nuse Illuminate\\Support\\Facades\\File;\n\nclass EditConfigFile\n{\n    use Abort"
  },
  {
    "path": "app/Actions/GenerateAppKey.php",
    "chars": 832,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\n\nclass GenerateAppKey\n{\n    use AbortsCommands;\n\n  "
  },
  {
    "path": "app/Actions/InitializeGitHubRepository.php",
    "chars": 1333,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\Actions\\Concerns\\InteractsWithGitHub;\nuse App\\ConsoleWriter;\nuse App\\Shell;\n\nclas"
  },
  {
    "path": "app/Actions/InitializeGitRepository.php",
    "chars": 1132,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\n\nclass InitializeGitRepository\n{\n    use AbortsComm"
  },
  {
    "path": "app/Actions/InstallBreeze.php",
    "chars": 1637,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\Actions\\Concerns\\InteractsWithComposer;\nuse App\\Actions\\Concerns\\InteractsWithNpm"
  },
  {
    "path": "app/Actions/InstallJetstream.php",
    "chars": 2149,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\Actions\\Concerns\\InteractsWithComposer;\nuse App\\Actions\\Concerns\\InteractsWithNpm"
  },
  {
    "path": "app/Actions/InstallLaravel.php",
    "chars": 1149,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\n\nclass InstallLaravel\n{\n    use AbortsCommands;\n\n  "
  },
  {
    "path": "app/Actions/InstallNpmDependencies.php",
    "chars": 900,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\n\nclass InstallNpmDependencies\n{\n    use AbortsComma"
  },
  {
    "path": "app/Actions/MigrateDatabase.php",
    "chars": 1838,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\nuse App\\Tools\\Database;\nuse PDOException;\n\nclass Mi"
  },
  {
    "path": "app/Actions/OpenInBrowser.php",
    "chars": 963,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\Environment;\nuse App\\Shell;\n\nclass OpenInBrowser\n{\n    use AbortsCommands;\n\n    p"
  },
  {
    "path": "app/Actions/OpenInEditor.php",
    "chars": 776,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\n\nclass OpenInEditor\n{\n    use AbortsCommands;\n\n    "
  },
  {
    "path": "app/Actions/PushToGitHub.php",
    "chars": 1657,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\n\nclass PushToGitHub\n{\n    public const WARNING_FAIL"
  },
  {
    "path": "app/Actions/RunAfterScript.php",
    "chars": 1023,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\nuse Illuminate\\Support\\Facades\\File;\n\nclass RunAfte"
  },
  {
    "path": "app/Actions/UpgradeSavedConfiguration.php",
    "chars": 5555,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Facades\\File;\nuse Illuminate\\Support\\Str;\n\nclas"
  },
  {
    "path": "app/Actions/ValetLink.php",
    "chars": 753,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\n\nclass ValetLink\n{\n    use AbortsCommands;\n\n    pro"
  },
  {
    "path": "app/Actions/ValetSecure.php",
    "chars": 766,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\n\nclass ValetSecure\n{\n    use AbortsCommands;\n\n    p"
  },
  {
    "path": "app/Actions/ValidateGitHubConfiguration.php",
    "chars": 3014,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\Actions\\Concerns\\InteractsWithGitHub;\nuse App\\Configuration\\LamboConfiguration;\nu"
  },
  {
    "path": "app/Actions/VerifyDependencies.php",
    "chars": 3150,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\ConsoleWriter;\nuse Symfony\\Component\\Process\\ExecutableFinder;\n\nclass VerifyDepen"
  },
  {
    "path": "app/Actions/VerifyPathAvailable.php",
    "chars": 1213,
    "preview": "<?php\n\nnamespace App\\Actions;\n\nuse App\\LamboException;\nuse Illuminate\\Support\\Facades\\File;\n\nclass VerifyPathAvailable\n{"
  },
  {
    "path": "app/Commands/.gitkeep",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "app/Commands/Debug.php",
    "chars": 6402,
    "preview": "<?php\n\nnamespace App\\Commands;\n\nuse App\\ConsoleWriter;\nuse Carbon\\Carbon;\nuse Dotenv\\Dotenv;\nuse Illuminate\\Support\\Arr;"
  },
  {
    "path": "app/Commands/EditAfter.php",
    "chars": 1547,
    "preview": "<?php\n\nnamespace App\\Commands;\n\nuse App\\Actions\\EditConfigFile;\nuse App\\Configuration\\CommandLineConfiguration;\nuse App\\"
  },
  {
    "path": "app/Commands/EditConfig.php",
    "chars": 1550,
    "preview": "<?php\n\nnamespace App\\Commands;\n\nuse App\\Actions\\EditConfigFile;\nuse App\\Configuration\\CommandLineConfiguration;\nuse App\\"
  },
  {
    "path": "app/Commands/HelpCommand.php",
    "chars": 358,
    "preview": "<?php\n\nnamespace App\\Commands;\n\nuse App\\Actions\\DisplayHelpScreen;\nuse App\\Actions\\DisplayLamboWelcome;\n\nclass HelpComma"
  },
  {
    "path": "app/Commands/LamboCommand.php",
    "chars": 602,
    "preview": "<?php\n\nnamespace App\\Commands;\n\nuse App\\ConsoleWriter;\nuse LaravelZero\\Framework\\Commands\\Command;\nuse Symfony\\Component"
  },
  {
    "path": "app/Commands/NewCommand.php",
    "chars": 9041,
    "preview": "<?php\n\nnamespace App\\Commands;\n\nuse App\\Actions\\CreateDatabase;\nuse App\\Actions\\CustomizeDotEnv;\nuse App\\Actions\\Display"
  },
  {
    "path": "app/Configuration/CommandLineConfiguration.php",
    "chars": 392,
    "preview": "<?php\n\nnamespace App\\Configuration;\n\nclass CommandLineConfiguration extends LamboConfiguration\n{\n    protected function "
  },
  {
    "path": "app/Configuration/LamboConfiguration.php",
    "chars": 2353,
    "preview": "<?php\n\nnamespace App\\Configuration;\n\nuse Illuminate\\Support\\Str;\n\nabstract class LamboConfiguration\n{\n    public const E"
  },
  {
    "path": "app/Configuration/SavedConfiguration.php",
    "chars": 552,
    "preview": "<?php\n\nnamespace App\\Configuration;\n\nuse Dotenv\\Dotenv;\nuse Illuminate\\Support\\Facades\\File;\n\nclass SavedConfiguration e"
  },
  {
    "path": "app/Configuration/SetConfig.php",
    "chars": 8714,
    "preview": "<?php\n\nnamespace App\\Configuration;\n\nuse App\\Actions\\InstallBreeze;\nuse App\\Actions\\InstallJetstream;\nuse App\\Commands\\D"
  },
  {
    "path": "app/Configuration/ShellConfiguration.php",
    "chars": 174,
    "preview": "<?php\n\nnamespace App\\Configuration;\n\nclass ShellConfiguration extends LamboConfiguration\n{\n    protected function getSet"
  },
  {
    "path": "app/ConsoleWriter.php",
    "chars": 3772,
    "preview": "<?php\n\nnamespace App;\n\nuse Illuminate\\Console\\OutputStyle;\nuse Symfony\\Component\\Process\\Process;\n\nclass ConsoleWriter e"
  },
  {
    "path": "app/Environment.php",
    "chars": 134,
    "preview": "<?php\n\nnamespace App;\n\nclass Environment\n{\n    public static function isMac(): bool\n    {\n        return PHP_OS === 'Dar"
  },
  {
    "path": "app/Helpers/GetTimezone.php",
    "chars": 271,
    "preview": "<?php\n\nnamespace App\\Helpers;\n\nuse IntlTimeZone;\n\nclass GetTimezone\n{\n    public function __invoke(): string\n    {\n     "
  },
  {
    "path": "app/LamboException.php",
    "chars": 82,
    "preview": "<?php\n\nnamespace App;\n\nuse Exception;\n\nclass LamboException extends Exception\n{\n}\n"
  },
  {
    "path": "app/LogsToConsole.php",
    "chars": 525,
    "preview": "<?php\n\nnamespace App;\n\ntrait LogsToConsole\n{\n    public function alert(string $message)\n    {\n        app('console')->al"
  },
  {
    "path": "app/Options.php",
    "chars": 4619,
    "preview": "<?php\n\nnamespace App;\n\nclass Options\n{\n    protected $options = [\n        /** Parameters first, then flags */\n        [\n"
  },
  {
    "path": "app/Providers/AppServiceProvider.php",
    "chars": 694,
    "preview": "<?php\n\nnamespace App\\Providers;\n\nuse Illuminate\\Support\\ServiceProvider;\n\nclass AppServiceProvider extends ServiceProvid"
  },
  {
    "path": "app/Shell.php",
    "chars": 1845,
    "preview": "<?php\n\nnamespace App;\n\nuse Illuminate\\Contracts\\Config\\Repository;\nuse Symfony\\Component\\Process\\Process;\n\nclass Shell\n{"
  },
  {
    "path": "app/Tools/Database.php",
    "chars": 1395,
    "preview": "<?php\n\nnamespace App\\Tools;\n\nuse PDO;\n\nclass Database\n{\n    private $dsn;\n    private $username;\n    private $password;\n"
  },
  {
    "path": "bin/testLambo.sh",
    "chars": 2548,
    "preview": "#!/usr/bin/env bash\n\n# ------------------------------------------------------------------------------\n# THIS SCRIPT WILL"
  },
  {
    "path": "bootstrap/app.php",
    "chars": 1529,
    "preview": "<?php\n\n/*\n|--------------------------------------------------------------------------\n| Create The Application\n|--------"
  },
  {
    "path": "box.json",
    "chars": 387,
    "preview": "{\n    \"chmod\": \"0755\",\n    \"directories\": [\n        \"app\",\n        \"bootstrap\",\n        \"config\",\n        \"stubs\",\n     "
  },
  {
    "path": "composer.json",
    "chars": 1286,
    "preview": "{\n    \"name\": \"tightenco/lambo\",\n    \"description\": \"Super-powered 'laravel new' with Laravel and Valet.\",\n    \"keywords"
  },
  {
    "path": "config/app.php",
    "chars": 2571,
    "preview": "<?php\n\nuse App\\Helpers\\GetTimezone;\n\nreturn [\n\n    /*\n    |-------------------------------------------------------------"
  },
  {
    "path": "config/commands.php",
    "chars": 2778,
    "preview": "<?php\n\nreturn [\n\n    /*\n    |--------------------------------------------------------------------------\n    | Default Co"
  },
  {
    "path": "lambo",
    "chars": 1940,
    "preview": "#!/usr/bin/env php\n<?php\n\ndefine('LARAVEL_START', microtime(true));\n\n/*\n|-----------------------------------------------"
  },
  {
    "path": "phpunit.xml.dist",
    "chars": 654,
    "preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<phpunit xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:noNam"
  },
  {
    "path": "readme.md",
    "chars": 10079,
    "preview": "![Lambo logo](https://raw.githubusercontent.com/tighten/lambo/main/lambo-banner.png)\n\n[![Run tests](https://github.com/t"
  },
  {
    "path": "stubs/after",
    "chars": 562,
    "preview": "#!/usr/bin/env bash\n\n# Install additional composer dependencies as you would from the command line.\n# echo \"\n# Installin"
  },
  {
    "path": "stubs/config",
    "chars": 210,
    "preview": "PROJECTPATH=\nMESSAGE=\"Initial commit.\"\nDEVELOP=false\nCODEEDITOR=\nBROWSER=\nLINK=false\nSECURE=false\nCREATE_DATABASE=false\n"
  },
  {
    "path": "tests/CreatesApplication.php",
    "chars": 382,
    "preview": "<?php\n\nnamespace Tests;\n\nuse Illuminate\\Contracts\\Console\\Kernel;\n\ntrait CreatesApplication\n{\n    /**\n     * Creates the"
  },
  {
    "path": "tests/Feature/CreateDatabaseTest.php",
    "chars": 1665,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\CreateDatabase;\nuse App\\Tools\\Database;\nuse Tests\\TestCase;\n\nclass Crea"
  },
  {
    "path": "tests/Feature/CustomizeDotEnvTest.php",
    "chars": 2612,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\CustomizeDotEnv;\nuse Illuminate\\Support\\Facades\\File;\nuse Tests\\TestCas"
  },
  {
    "path": "tests/Feature/EditConfigFileTest.php",
    "chars": 6501,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\EditConfigFile;\nuse App\\LamboException;\nuse Illuminate\\Support\\Facades\\"
  },
  {
    "path": "tests/Feature/Fakes/FakeProcess.php",
    "chars": 1282,
    "preview": "<?php\n\nnamespace Tests\\Feature\\Fakes;\n\nclass FakeProcess\n{\n    public $isSuccessful;\n    public $failedCommand;\n\n    pri"
  },
  {
    "path": "tests/Feature/Fixtures/.lambo/commented_configuration",
    "chars": 388,
    "preview": "CODEEDITOR=vim\n#QUIET=true\n#AUTH=false\n#NODE=\n\n# -----------------------------------------------------------------------"
  },
  {
    "path": "tests/Feature/Fixtures/.lambo/config",
    "chars": 302,
    "preview": "CONFIGURATION_OPTION=foo\n#MISSING_CONFIGURATION_OPTION=foo\nCONFIGURATION_OPTION_NO_VALUE\nCONFIGURATION_OPTION_EMPTY_VALU"
  },
  {
    "path": "tests/Feature/Fixtures/.lambo/old_configuration",
    "chars": 43,
    "preview": "CODEEDITOR=vim\nQUIET=true\nAUTH=false\nNODE=\n"
  },
  {
    "path": "tests/Feature/Fixtures/composer-with-laravel-jetstream.json",
    "chars": 63,
    "preview": "{\n    \"require\": {\n        \"laravel/jetstream\": \"^1.0\"\n    }\n}\n"
  },
  {
    "path": "tests/Feature/Fixtures/composer-without-laravel-jetstream.json",
    "chars": 27,
    "preview": "{\n    \"require\": {\n    }\n}\n"
  },
  {
    "path": "tests/Feature/Fixtures/composer.json",
    "chars": 63,
    "preview": "{\n    \"require\": {\n        \"laravel/jetstream\": \"^1.0\"\n    }\n}\n"
  },
  {
    "path": "tests/Feature/Fixtures/package-silent.json",
    "chars": 184,
    "preview": "{\"scripts\":{\"development\":\"cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --no-progress --hide-modul"
  },
  {
    "path": "tests/Feature/Fixtures/package.json",
    "chars": 195,
    "preview": "{\n  \"scripts\": {\n    \"development\": \"cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hid"
  },
  {
    "path": "tests/Feature/GenerateAppKeyTest.php",
    "chars": 877,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\GenerateAppKey;\nuse App\\LamboException;\nuse Tests\\Feature\\Fakes\\FakePro"
  },
  {
    "path": "tests/Feature/InitializeGitHubRepositoryTest.php",
    "chars": 7669,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\Concerns\\InteractsWithGitHub;\nuse App\\Actions\\InitializeGitHubRepositor"
  },
  {
    "path": "tests/Feature/InitializeGitRepositoryTest.php",
    "chars": 3346,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\InitializeGitRepository;\nuse App\\LamboException;\nuse Tests\\Feature\\Fake"
  },
  {
    "path": "tests/Feature/InstallBreezeTest.php",
    "chars": 4765,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\InstallBreeze;\nuse App\\LamboException;\nuse App\\Shell;\nuse Tests\\TestCas"
  },
  {
    "path": "tests/Feature/InstallJetstreamTest.php",
    "chars": 5159,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\InstallJetstream;\nuse App\\LamboException;\nuse App\\Shell;\nuse Tests\\Test"
  },
  {
    "path": "tests/Feature/InstallLaravelTest.php",
    "chars": 1845,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\InstallLaravel;\nuse App\\LamboException;\nuse Tests\\Feature\\Fakes\\FakePro"
  },
  {
    "path": "tests/Feature/InstallNpmDependenciesTest.php",
    "chars": 1339,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\InstallNpmDependencies;\nuse App\\LamboException;\nuse Tests\\Feature\\Fakes"
  },
  {
    "path": "tests/Feature/LamboTestEnvironment.php",
    "chars": 474,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse Illuminate\\Support\\Facades\\File;\n\ntrait LamboTestEnvironment\n{\n    protected functi"
  },
  {
    "path": "tests/Feature/MigrateDatabaseTest.php",
    "chars": 3052,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\MigrateDatabase;\nuse App\\Shell;\nuse App\\Tools\\Database;\nuse Tests\\Featu"
  },
  {
    "path": "tests/Feature/OpenInBrowserTest.php",
    "chars": 2385,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\OpenInBrowser;\nuse App\\Environment;\nuse App\\Shell;\nuse Tests\\TestCase;\n"
  },
  {
    "path": "tests/Feature/OpenInEditorTest.php",
    "chars": 1150,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\OpenInEditor;\nuse App\\LamboException;\nuse Tests\\Feature\\Fakes\\FakeProce"
  },
  {
    "path": "tests/Feature/PushToGitHubTest.php",
    "chars": 4233,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\PushToGitHub;\nuse App\\ConsoleWriter;\nuse App\\Shell;\nuse Tests\\Feature\\F"
  },
  {
    "path": "tests/Feature/RunAfterScriptTest.php",
    "chars": 2219,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\RunAfterScript;\nuse App\\LamboException;\nuse Illuminate\\Support\\Facades\\"
  },
  {
    "path": "tests/Feature/SignatureBuilderTest.php",
    "chars": 1885,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Commands\\NewCommand;\nuse Tests\\TestCase;\n\nclass SignatureBuilderTest extends Te"
  },
  {
    "path": "tests/Feature/UpgradeSavedConfigurationTest.php",
    "chars": 2637,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\UpgradeSavedConfiguration;\nuse Carbon\\Carbon;\nuse Tests\\TestCase;\n\nclas"
  },
  {
    "path": "tests/Feature/ValetLinkTest.php",
    "chars": 910,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\ValetLink;\nuse App\\LamboException;\nuse Tests\\Feature\\Fakes\\FakeProcess;"
  },
  {
    "path": "tests/Feature/ValetSecureTest.php",
    "chars": 907,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\ValetSecure;\nuse App\\LamboException;\nuse Tests\\Feature\\Fakes\\FakeProces"
  },
  {
    "path": "tests/Feature/ValidateGitHubConfigurationTest.php",
    "chars": 4884,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\ValidateGitHubConfiguration;\nuse App\\Configuration\\LamboConfiguration;\n"
  },
  {
    "path": "tests/Feature/VerifyDependenciesTest.php",
    "chars": 2816,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\VerifyDependencies;\nuse App\\LamboException;\nuse Symfony\\Component\\Proce"
  },
  {
    "path": "tests/Feature/VerifyPathAvailableTest.php",
    "chars": 5043,
    "preview": "<?php\n\nnamespace Tests\\Feature;\n\nuse App\\Actions\\VerifyPathAvailable;\nuse App\\LamboException;\nuse Exception;\nuse Illumin"
  },
  {
    "path": "tests/TestCase.php",
    "chars": 2185,
    "preview": "<?php\n\nnamespace Tests;\n\nuse App\\ConsoleWriter;\nuse App\\Shell;\nuse LaravelZero\\Framework\\Testing\\TestCase as BaseTestCas"
  },
  {
    "path": "tests/Unit/CommandLineConfigurationTest.php",
    "chars": 3080,
    "preview": "<?php\n\nnamespace Tests\\Unit;\n\nuse App\\Configuration\\CommandLineConfiguration;\nuse Illuminate\\Support\\Arr;\nuse LaravelZer"
  },
  {
    "path": "tests/Unit/Fakes/FakeInput.php",
    "chars": 2571,
    "preview": "<?php\n\nnamespace Tests\\Unit\\Fakes;\n\nuse Exception;\nuse Illuminate\\Support\\Arr;\nuse Symfony\\Component\\Console\\Input\\Input"
  },
  {
    "path": "tests/Unit/GetTimezoneTest.php",
    "chars": 574,
    "preview": "<?php\n\nnamespace Tests\\Unit;\n\nuse App\\Helpers\\GetTimezone;\nuse IntlTimeZone;\nuse Tests\\TestCase;\n\nclass GetTimezoneTest "
  },
  {
    "path": "tests/Unit/SavedConfigurationTest.php",
    "chars": 3193,
    "preview": "<?php\n\nnamespace Tests\\Unit;\n\nuse App\\Configuration\\SavedConfiguration;\nuse Tests\\TestCase;\n\nclass SavedConfigurationTes"
  },
  {
    "path": "tests/Unit/SetConfigTest.php",
    "chars": 32658,
    "preview": "<?php\n\nnamespace Tests\\Unit;\n\nuse App\\Actions\\InstallBreeze;\nuse App\\Actions\\InstallJetstream;\nuse App\\Commands\\NewComma"
  },
  {
    "path": "tests/Unit/ShellConfigurationTest.php",
    "chars": 1462,
    "preview": "<?php\n\nnamespace Tests\\Unit;\n\nuse App\\Configuration\\ShellConfiguration;\nuse Illuminate\\Support\\Arr;\nuse Tests\\TestCase;\n"
  },
  {
    "path": "tlint.json",
    "chars": 96,
    "preview": "{\n    \"preset\": \"tighten\",\n    \"disabled\": [],\n    \"excluded\": [\n        \"node_modules\"\n    ]\n}\n"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the tighten/lambo GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 107 files (226.1 KB), approximately 54.9k tokens, and a symbol index with 434 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!