diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5b3baf03..b7d3b9fc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -14,17 +14,26 @@ permissions: jobs: tests: - runs-on: ubuntu-22.04 + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash strategy: fail-fast: true matrix: + os: [ ubuntu-22.04, windows-latest ] php: [ 8.2, 8.3, 8.4 ] laravel: [ 11, 12 ] - name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} + name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.os }} steps: + - name: Set git to use LF + run: | + git config --global core.autocrlf false + git config --global core.eol lf + - name: Checkout code uses: actions/checkout@v4 @@ -32,9 +41,9 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: dom, curl, libxml, mbstring, zip + extensions: dom, curl, libxml, mbstring, zip, fileinfo, pdo, sqlite, pdo_sqlite ini-values: error_reporting=E_ALL - tools: composer:v2 + tools: composer:v2.8 coverage: none - name: Setup SSH Keys @@ -46,22 +55,31 @@ jobs: - name: Install dependencies run: | - composer update --prefer-dist --no-interaction --no-progress --with="illuminate/contracts:^${{ matrix.laravel }}" + composer update --prefer-dist --no-interaction --no-progress --with='illuminate/contracts:^${{ matrix.laravel }}' - name: Execute tests run: vendor/bin/pest test-l10: - runs-on: ubuntu-22.04 + runs-on: ${{ matrix.os }} + defaults: + run: + shell: bash strategy: fail-fast: true matrix: + os: [ ubuntu-22.04, windows-latest ] php: [ 8.1, 8.2 ] laravel: [ 10 ] - name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} + name: PHP ${{ matrix.php }} - Laravel ${{ matrix.laravel }} - ${{ matrix.os }} steps: + - name: Set git to use LF + run: | + git config --global core.autocrlf false + git config --global core.eol lf + - name: Checkout code uses: actions/checkout@v4 @@ -69,9 +87,9 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: dom, curl, libxml, mbstring, zip + extensions: dom, curl, libxml, mbstring, zip, fileinfo, pdo, sqlite, pdo_sqlite ini-values: error_reporting=E_ALL - tools: composer:v2 + tools: composer:v2.8 coverage: none - name: Setup SSH Keys @@ -83,7 +101,7 @@ jobs: - name: Install dependencies run: | - composer update --prefer-dist --no-interaction --no-progress --with="illuminate/contracts:^${{ matrix.laravel }}" + composer update --prefer-dist --no-interaction --no-progress --with="illuminate/contracts:^${{ matrix.laravel }}.0" - name: Execute tests run: vendor/bin/pest diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b3f76ec..cbedbb0d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Release Notes -## [Unreleased](https://github.com/laravel/boost/compare/v1.1.2...main) +## [Unreleased](https://github.com/laravel/boost/compare/v1.1.3...main) + +## [v1.1.3](https://github.com/laravel/boost/compare/v1.1.2...v1.1.3) - 2025-09-04 + +### What's Changed + +* fix: package priorities should work on php8.1 by [@ashleyhindle](https://github.com/ashleyhindle) in https://github.com/laravel/boost/pull/243 + +**Full Changelog**: https://github.com/laravel/boost/compare/v1.1.2...v1.1.3 ## [v1.1.2](https://github.com/laravel/boost/compare/v1.1.1...v1.1.2) - 2025-09-04 diff --git a/src/Install/GuidelineComposer.php b/src/Install/GuidelineComposer.php index 020eb903..85a06e30 100644 --- a/src/Install/GuidelineComposer.php +++ b/src/Install/GuidelineComposer.php @@ -296,7 +296,8 @@ protected function guidelinePath(string $path): ?string } // The path is not a custom guideline, check if the user has an override for this - $relativePath = ltrim(str_replace([realpath(__DIR__.'/../../'), '.ai/'], '', $path), '/'); + $basePath = realpath(__DIR__.'/../../'); + $relativePath = ltrim(str_replace([$basePath, '.ai'.DIRECTORY_SEPARATOR, '.ai/'], '', $path), '/\\'); $customPath = $this->prependUserGuidelinePath($relativePath); return file_exists($customPath) ? $customPath : $path; diff --git a/src/Install/Mcp/FileWriter.php b/src/Install/Mcp/FileWriter.php index dce5e66d..98c508e5 100644 --- a/src/Install/Mcp/FileWriter.php +++ b/src/Install/Mcp/FileWriter.php @@ -188,6 +188,9 @@ protected function generateServerJson(string $key, array $serverConfig, int $bas { $json = json_encode($serverConfig, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + // Normalize line endings to Unix style + $json = str_replace("\r\n", "\n", $json); + // If no indentation needed, return as-is if (empty($baseIndent)) { return '"'.$key.'": '.$json; @@ -380,6 +383,11 @@ protected function writeJsonConfig(array $config): bool { $json = json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES); + // Normalize line endings to Unix style + if ($json) { + $json = str_replace("\r\n", "\n", $json); + } + return $json && $this->writeFile($json); } diff --git a/tests/Feature/Console/InstallCommandMultiselectTest.php b/tests/Feature/Console/InstallCommandMultiselectTest.php index 1027efdf..9ad7d53d 100644 --- a/tests/Feature/Console/InstallCommandMultiselectTest.php +++ b/tests/Feature/Console/InstallCommandMultiselectTest.php @@ -2,110 +2,91 @@ declare(strict_types=1); -namespace Tests\Feature\Console; - use Laravel\Prompts\Key; use Laravel\Prompts\Prompt; -use Tests\TestCase; -class InstallCommandMultiselectTest extends TestCase -{ - /** - * Test that multiselect returns keys when given an associative array. - */ - public function test_multiselect_returns_keys_for_associative_array(): void - { - // Mock the prompt to simulate user selecting options - // Note: mcp_server is already selected by default, so we don't toggle it - Prompt::fake([ - Key::DOWN, // Move to second option (ai_guidelines) - Key::SPACE, // Select second option - Key::ENTER, // Submit - ]); +test('multiselect returns keys for associative array', function () { + // Mock the prompt to simulate user selecting options + // Note: mcp_server is already selected by default, so we don't toggle it + Prompt::fake([ + Key::DOWN, // Move to second option (ai_guidelines) + Key::SPACE, // Select second option + Key::ENTER, // Submit + ]); - $result = \Laravel\Prompts\multiselect( - label: 'What shall we install?', - options: [ - 'mcp_server' => 'Boost MCP Server', - 'ai_guidelines' => 'Package AI Guidelines', - 'style_guidelines' => 'Laravel Style AI Guidelines', - ], - default: ['mcp_server'] - ); + $result = \Laravel\Prompts\multiselect( + label: 'What shall we install?', + options: [ + 'mcp_server' => 'Boost MCP Server', + 'ai_guidelines' => 'Package AI Guidelines', + 'style_guidelines' => 'Laravel Style AI Guidelines', + ], + default: ['mcp_server'] + ); - // Assert that we get the keys, not the values - $this->assertIsArray($result); - $this->assertCount(2, $result, 'Should have 2 items selected'); - $this->assertContains('mcp_server', $result); - $this->assertContains('ai_guidelines', $result); - $this->assertNotContains('Boost MCP Server', $result); - $this->assertNotContains('Package AI Guidelines', $result); - } + // Assert that we get the keys, not the values + expect($result)->toBeArray(); + expect($result)->toHaveCount(2, 'Should have 2 items selected'); + expect($result)->toContain('mcp_server'); + expect($result)->toContain('ai_guidelines'); + expect($result)->not->toContain('Boost MCP Server'); + expect($result)->not->toContain('Package AI Guidelines'); +})->skipOnWindows(); - /** - * Test multiselect with numeric indexed array returns values. - */ - public function test_multiselect_returns_values_for_indexed_array(): void - { - Prompt::fake([ - Key::SPACE, // Select first option - Key::DOWN, // Move to second option - Key::SPACE, // Select second option - Key::ENTER, // Submit - ]); +test('multiselect returns values for indexed array', function () { + Prompt::fake([ + Key::SPACE, // Select first option + Key::DOWN, // Move to second option + Key::SPACE, // Select second option + Key::ENTER, // Submit + ]); - $result = \Laravel\Prompts\multiselect( - label: 'Select options', - options: ['Option 1', 'Option 2', 'Option 3'], - default: [] - ); + $result = \Laravel\Prompts\multiselect( + label: 'Select options', + options: ['Option 1', 'Option 2', 'Option 3'], + default: [] + ); - // For indexed arrays, it returns the actual values - $this->assertIsArray($result); - $this->assertContains('Option 1', $result); - $this->assertContains('Option 2', $result); - } + // For indexed arrays, it returns the actual values + expect($result)->toBeArray(); + expect($result)->toContain('Option 1'); + expect($result)->toContain('Option 2'); +})->skipOnWindows(); - /** - * Test that demonstrates multiselect behavior is consistent with InstallCommand expectations. - * This ensures Laravel 10/11 compatibility. - */ - public function test_multiselect_behavior_matches_install_command_expectations(): void - { - // Test the exact same structure used in InstallCommand::selectBoostFeatures() - // Note: mcp_server and ai_guidelines are already selected by default - Prompt::fake([ - Key::DOWN, // Move to ai_guidelines (already selected) - Key::DOWN, // Move to style_guidelines - Key::SPACE, // Select style_guidelines - Key::ENTER, // Submit - ]); +test('multiselect behavior matches install command expectations', function () { + // Test the exact same structure used in InstallCommand::selectBoostFeatures() + // Note: mcp_server and ai_guidelines are already selected by default + Prompt::fake([ + Key::DOWN, // Move to ai_guidelines (already selected) + Key::DOWN, // Move to style_guidelines + Key::SPACE, // Select style_guidelines + Key::ENTER, // Submit + ]); - $toInstallOptions = [ - 'mcp_server' => 'Boost MCP Server', - 'ai_guidelines' => 'Package AI Guidelines (i.e. Framework, Inertia, Pest)', - 'style_guidelines' => 'Laravel Style AI Guidelines', - ]; + $toInstallOptions = [ + 'mcp_server' => 'Boost MCP Server', + 'ai_guidelines' => 'Package AI Guidelines (i.e. Framework, Inertia, Pest)', + 'style_guidelines' => 'Laravel Style AI Guidelines', + ]; - $result = \Laravel\Prompts\multiselect( - label: 'What shall we install?', - options: $toInstallOptions, - default: ['mcp_server', 'ai_guidelines'], - required: true, - hint: 'Style guidelines are best for new projects', - ); + $result = \Laravel\Prompts\multiselect( + label: 'What shall we install?', + options: $toInstallOptions, + default: ['mcp_server', 'ai_guidelines'], + required: true, + hint: 'Style guidelines are best for new projects', + ); - // Verify we get keys that can be used with in_array checks - $this->assertIsArray($result); - $this->assertCount(3, $result); // All 3 selected (2 default + 1 added) + // Verify we get keys that can be used with in_array checks + expect($result)->toBeArray(); + expect($result)->toHaveCount(3); // All 3 selected (2 default + 1 added) - // These are the exact checks used in InstallCommand - $this->assertTrue(in_array('mcp_server', $result, true)); - $this->assertTrue(in_array('ai_guidelines', $result, true)); - $this->assertTrue(in_array('style_guidelines', $result, true)); + // These are the exact checks used in InstallCommand + expect(in_array('mcp_server', $result, true))->toBeTrue(); + expect(in_array('ai_guidelines', $result, true))->toBeTrue(); + expect(in_array('style_guidelines', $result, true))->toBeTrue(); - // Verify it doesn't contain the display values - $this->assertFalse(in_array('Boost MCP Server', $result, true)); - $this->assertFalse(in_array('Package AI Guidelines (i.e. Framework, Inertia, Pest)', $result, true)); - } -} + // Verify it doesn't contain the display values + expect(in_array('Boost MCP Server', $result, true))->toBeFalse(); + expect(in_array('Package AI Guidelines (i.e. Framework, Inertia, Pest)', $result, true))->toBeFalse(); +})->skipOnWindows(); diff --git a/tests/Feature/Mcp/Tools/DatabaseSchemaTest.php b/tests/Feature/Mcp/Tools/DatabaseSchemaTest.php index ca08d1c2..f7397876 100644 --- a/tests/Feature/Mcp/Tools/DatabaseSchemaTest.php +++ b/tests/Feature/Mcp/Tools/DatabaseSchemaTest.php @@ -22,6 +22,7 @@ } // Build a throw-away table that we expect in the dump. + Schema::dropIfExists('examples'); Schema::create('examples', function (Blueprint $table) { $table->id(); $table->string('name'); diff --git a/tests/Unit/Install/GuidelineWriterTest.php b/tests/Unit/Install/GuidelineWriterTest.php index 892ee6ad..9422c804 100644 --- a/tests/Unit/Install/GuidelineWriterTest.php +++ b/tests/Unit/Install/GuidelineWriterTest.php @@ -47,7 +47,7 @@ expect(fn () => $writer->write('test guidelines')) ->toThrow(RuntimeException::class, 'Failed to create directory: /root/boost_test'); -}); +})->skipOnWindows(); test('it writes guidelines to new file', function () { $tempFile = tempnam(sys_get_temp_dir(), 'boost_test_'); @@ -150,7 +150,7 @@ expect(fn () => $writer->write('test guidelines')) ->toThrow(RuntimeException::class, "Failed to open file: {$dirPath}"); -}); +})->skipOnWindows(); test('it preserves file content structure with proper spacing', function () { $tempFile = tempnam(sys_get_temp_dir(), 'boost_test_');