diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 4df9804..f398d90 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -48,7 +48,7 @@ jobs: version: 2.x - name: Directory Permissions - run: sudo chown -R $(whoami) skeleton vendor/pestphp/pest/.temp + run: sudo chown -R $(whoami) ./vendor/pestphp/pest/.temp ./vendor/orchestra/testbench-core/laravel/bootstrap/cache - name: Execute tests - coverage threshold 90% run: ./vendor/bin/pest --bail --retry --coverage --min=90 --coverage-clover clover.xml diff --git a/.gitignore b/.gitignore index fbec92b..f613b17 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ -DS_Store +.DS_Store /vendor /skeleton diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..c5482ca --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "core"] + path = core + url = https://github.com/media-code/workspace-core + branch = main diff --git a/LICENSE.md b/LICENSE.md index 1fa32c1..0e78c26 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,163 +1,21 @@ -GNU Lesser General Public License -================================= - -_Version 3, 29 June 2007_ -_Copyright © 2007 Free Software Foundation, Inc. <>_ - -Everyone is permitted to copy and distribute verbatim copies -of this license document, but changing it is not allowed. - - -This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - -### 0. Additional Definitions - -As used herein, “this License” refers to version 3 of the GNU Lesser -General Public License, and the “GNU GPL” refers to version 3 of the GNU -General Public License. - -“The Library” refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - -An “Application” is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - -A “Combined Work” is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the “Linked -Version”. - -The “Minimal Corresponding Source” for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - -The “Corresponding Application Code” for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - -### 1. Exception to Section 3 of the GNU GPL - -You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - -### 2. Conveying Modified Versions - -If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - -* **a)** under this License, provided that you make a good faith effort to -ensure that, in the event an Application does not supply the -function or data, the facility still operates, and performs -whatever part of its purpose remains meaningful, or - -* **b)** under the GNU GPL, with none of the additional permissions of -this License applicable to that copy. - -### 3. Object Code Incorporating Material from Library Header Files - -The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - -* **a)** Give prominent notice with each copy of the object code that the -Library is used in it and that the Library and its use are -covered by this License. -* **b)** Accompany the object code with a copy of the GNU GPL and this license -document. - -### 4. Combined Works - -You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - -* **a)** Give prominent notice with each copy of the Combined Work that -the Library is used in it and that the Library and its use are -covered by this License. - -* **b)** Accompany the Combined Work with a copy of the GNU GPL and this license -document. - -* **c)** For a Combined Work that displays copyright notices during -execution, include the copyright notice for the Library among -these notices, as well as a reference directing the user to the -copies of the GNU GPL and this license document. - -* **d)** Do one of the following: - - **0)** Convey the Minimal Corresponding Source under the terms of this -License, and the Corresponding Application Code in a form -suitable for, and under terms that permit, the user to -recombine or relink the Application with a modified version of -the Linked Version to produce a modified Combined Work, in the -manner specified by section 6 of the GNU GPL for conveying -Corresponding Source. - - **1)** Use a suitable shared library mechanism for linking with the -Library. A suitable mechanism is one that **(a)** uses at run time -a copy of the Library already present on the user's computer -system, and **(b)** will operate properly with a modified version -of the Library that is interface-compatible with the Linked -Version. - -* **e)** Provide Installation Information, but only if you would otherwise -be required to provide such information under section 6 of the -GNU GPL, and only to the extent that such information is -necessary to install and execute a modified version of the -Combined Work produced by recombining or relinking the -Application with a modified version of the Linked Version. (If -you use option **4d0**, the Installation Information must accompany -the Minimal Corresponding Source and Corresponding Application -Code. If you use option **4d1**, you must provide the Installation -Information in the manner specified by section 6 of the GNU GPL -for conveying Corresponding Source.) - -### 5. Combined Libraries - -You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - -* **a)** Accompany the combined library with a copy of the same work based -on the Library, uncombined with any other library facilities, -conveyed under the terms of this License. -* **b)** Give prominent notice with the combined library that part of it -is a work based on the Library, and explaining where to find the -accompanying uncombined form of the same work. - -### 6. Revised Versions of the GNU Lesser General Public License - -The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License “or any later version” -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - -If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. +The MIT License (MIT) + +Copyright (c) 2023 Gedachtegoed + +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. \ No newline at end of file diff --git a/README.md b/README.md index 794bd99..05ab2dc 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Extendible workspace configurator for Laravel to effortlessly keep linters, fixe [![codestyle](https://github.com/media-code/workspace/actions/workflows/codestyle.yml/badge.svg)](https://github.com/media-code/workspace/actions/workflows/codestyle.yml) [![tests](https://github.com/media-code/workspace/actions/workflows/tests.yml/badge.svg)](https://github.com/media-code/workspace/actions/workflows/tests.yml) [![coverage](https://img.shields.io/codecov/c/github/media-code/workspace?token=ON4MTY8C1B&color=45%2C190%2C65)](https://codecov.io/gh/media-code/workspace) +[![coverage](https://img.shields.io/codecov/c/github/media-code/workspace-core?label=core%20coverage&token=ON4MTY8C1B&color=45%2C190%2C65)](https://codecov.io/gh/media-code/workspace-core) diff --git a/composer.json b/composer.json index 0fe3597..1900d66 100644 --- a/composer.json +++ b/composer.json @@ -36,9 +36,19 @@ "test": "vendor/bin/testbench package:test --bail --retry" }, +"repositories": [ + { + "type": "vcs", + "url": "https://github.com/media-code/workspace-core", + "options": { + "symlink": false + } + } + ], "require": { "php": "^8.1.0", - "illuminate/support": "^10.23" + "illuminate/support": "^10.23", + "gedachtegoed/workspace-core": "^0.0.1" }, "require-dev": { "friendsofphp/php-cs-fixer": "^3.30", @@ -76,6 +86,10 @@ { "name": "timacdonald/callable-fake", "url": "https://github.com/timacdonald/callable-fake" + }, + { + "name": "gedachtegoed/workspace-core", + "url": "https://github.com/media-code/workspace-core" } ] } diff --git a/composer.lock b/composer.lock index 7c39ac8..1679f84 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3ca370d928acaf399eecee067af4a40a", + "content-hash": "00cbdc4751bcf4019cfb1df03816d139", "packages": [ { "name": "brick/math", @@ -367,16 +367,16 @@ }, { "name": "egulias/email-validator", - "version": "4.0.1", + "version": "4.0.2", "source": { "type": "git", "url": "https://github.com/egulias/EmailValidator.git", - "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff" + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/3a85486b709bc384dae8eb78fb2eec649bdb64ff", - "reference": "3a85486b709bc384dae8eb78fb2eec649bdb64ff", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/ebaaf5be6c0286928352e054f2d5125608e5405e", + "reference": "ebaaf5be6c0286928352e054f2d5125608e5405e", "shasum": "" }, "require": { @@ -385,8 +385,8 @@ "symfony/polyfill-intl-idn": "^1.26" }, "require-dev": { - "phpunit/phpunit": "^9.5.27", - "vimeo/psalm": "^4.30" + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" }, "suggest": { "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" @@ -422,7 +422,7 @@ ], "support": { "issues": "https://github.com/egulias/EmailValidator/issues", - "source": "https://github.com/egulias/EmailValidator/tree/4.0.1" + "source": "https://github.com/egulias/EmailValidator/tree/4.0.2" }, "funding": [ { @@ -430,7 +430,7 @@ "type": "github" } ], - "time": "2023-01-14T14:17:03+00:00" + "time": "2023-10-06T06:47:41+00:00" }, { "name": "fruitcake/php-cors", @@ -503,6 +503,104 @@ ], "time": "2022-02-20T15:07:15+00:00" }, + { + "name": "gedachtegoed/workspace-core", + "version": "v0.0.1", + "source": { + "type": "git", + "url": "https://github.com/media-code/workspace-core.git", + "reference": "b6c37027f3cb60721965cc9a9972e35635f60188" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/media-code/workspace-core/zipball/b6c37027f3cb60721965cc9a9972e35635f60188", + "reference": "b6c37027f3cb60721965cc9a9972e35635f60188", + "shasum": "" + }, + "require": { + "illuminate/support": "^10.23", + "php": "^8.1.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.30", + "laravel/pint": "^1.13", + "nunomaduro/larastan": "^2.0", + "orchestra/testbench": "^8.12", + "pestphp/pest": "^2.20", + "squizlabs/php_codesniffer": "^3.7", + "symfony/thanks": "^1.2", + "tightenco/duster": "^2.4", + "tightenco/tlint": "^9.1", + "timacdonald/callable-fake": "^1.6" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Gedachtegoed\\Workspace\\Core\\ServiceProvider" + ] + }, + "thanks": [ + { + "name": "tightenco/duster", + "url": "https://github.com/tighten/duster" + }, + { + "name": "laravel/prompts", + "url": "https://github.com/laravel/prompts" + }, + { + "name": "timacdonald/callable-fake", + "url": "https://github.com/timacdonald/callable-fake" + } + ] + }, + "autoload": { + "psr-4": { + "Gedachtegoed\\Workspace\\Core\\": "src/", + "Gedachtegoed\\Workspace\\Core\\Tests\\": "tests/" + } + }, + "scripts": { + "lint": [ + "vendor/bin/duster lint" + ], + "fix": [ + "vendor/bin/duster fix" + ], + "analyze": [ + "vendor/bin/phpstan analyse" + ], + "baseline": [ + "vendor/bin/phpstan analyse --generate-baseline" + ], + "test": [ + "vendor/bin/testbench package:test --bail --retry" + ] + }, + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Willem Leuverink", + "email": "willem@leuver.ink", + "homepage": "https://leuver.ink" + } + ], + "description": "Core for building your own Portable Workspace", + "support": { + "source": "https://github.com/media-code/workspace-core/tree/v0.0.1", + "issues": "https://github.com/media-code/workspace-core/issues" + }, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/gwleuverink" + } + ], + "time": "2023-10-09T20:38:21+00:00" + }, { "name": "graham-campbell/result-type", "version": "v1.1.1", @@ -647,16 +745,16 @@ }, { "name": "laravel/framework", - "version": "v10.26.2", + "version": "v10.27.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "6e5440f7c518f26b4495e5d7e4796ec239e26df9" + "reference": "616f81bd6dd8aa2e26a9fc21d9c95e98bd30803b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/6e5440f7c518f26b4495e5d7e4796ec239e26df9", - "reference": "6e5440f7c518f26b4495e5d7e4796ec239e26df9", + "url": "https://api.github.com/repos/laravel/framework/zipball/616f81bd6dd8aa2e26a9fc21d9c95e98bd30803b", + "reference": "616f81bd6dd8aa2e26a9fc21d9c95e98bd30803b", "shasum": "" }, "require": { @@ -843,7 +941,7 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2023-10-03T14:24:20+00:00" + "time": "2023-10-09T15:15:28+00:00" }, { "name": "laravel/prompts", @@ -1152,16 +1250,16 @@ }, { "name": "league/flysystem", - "version": "3.16.0", + "version": "3.17.0", "source": { "type": "git", "url": "https://github.com/thephpleague/flysystem.git", - "reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729" + "reference": "bd4c9b26849d82364119c68429541f1631fba94b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/4fdf372ca6b63c6e281b1c01a624349ccb757729", - "reference": "4fdf372ca6b63c6e281b1c01a624349ccb757729", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/bd4c9b26849d82364119c68429541f1631fba94b", + "reference": "bd4c9b26849d82364119c68429541f1631fba94b", "shasum": "" }, "require": { @@ -1179,8 +1277,8 @@ "symfony/http-client": "<5.2" }, "require-dev": { - "async-aws/s3": "^1.5", - "async-aws/simple-s3": "^1.1", + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", "aws/aws-sdk-php": "^3.220.0", "composer/semver": "^3.0", "ext-fileinfo": "*", @@ -1226,7 +1324,7 @@ ], "support": { "issues": "https://github.com/thephpleague/flysystem/issues", - "source": "https://github.com/thephpleague/flysystem/tree/3.16.0" + "source": "https://github.com/thephpleague/flysystem/tree/3.17.0" }, "funding": [ { @@ -1238,7 +1336,7 @@ "type": "github" } ], - "time": "2023-09-07T19:22:17+00:00" + "time": "2023-10-05T20:15:05+00:00" }, { "name": "league/flysystem-local", @@ -1565,16 +1663,16 @@ }, { "name": "nette/schema", - "version": "v1.2.4", + "version": "v1.2.5", "source": { "type": "git", "url": "https://github.com/nette/schema.git", - "reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab" + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/schema/zipball/c9ff517a53903b3d4e29ec547fb20feecb05b8ab", - "reference": "c9ff517a53903b3d4e29ec547fb20feecb05b8ab", + "url": "https://api.github.com/repos/nette/schema/zipball/0462f0166e823aad657c9224d0f849ecac1ba10a", + "reference": "0462f0166e823aad657c9224d0f849ecac1ba10a", "shasum": "" }, "require": { @@ -1621,9 +1719,9 @@ ], "support": { "issues": "https://github.com/nette/schema/issues", - "source": "https://github.com/nette/schema/tree/v1.2.4" + "source": "https://github.com/nette/schema/tree/v1.2.5" }, - "time": "2023-08-05T18:56:25+00:00" + "time": "2023-10-05T20:37:59+00:00" }, { "name": "nette/utils", @@ -4829,16 +4927,16 @@ "packages-dev": [ { "name": "brianium/paratest", - "version": "v7.2.8", + "version": "v7.2.9", "source": { "type": "git", "url": "https://github.com/paratestphp/paratest.git", - "reference": "882b02d197328138686bb06ce7d8cbb98fc0a16c" + "reference": "1f9e41c0779be4540654d92a9314016713f5e62c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/paratestphp/paratest/zipball/882b02d197328138686bb06ce7d8cbb98fc0a16c", - "reference": "882b02d197328138686bb06ce7d8cbb98fc0a16c", + "url": "https://api.github.com/repos/paratestphp/paratest/zipball/1f9e41c0779be4540654d92a9314016713f5e62c", + "reference": "1f9e41c0779be4540654d92a9314016713f5e62c", "shasum": "" }, "require": { @@ -4846,13 +4944,13 @@ "ext-pcre": "*", "ext-reflection": "*", "ext-simplexml": "*", - "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1", + "fidry/cpu-core-counter": "^0.5.1", "jean85/pretty-package-versions": "^2.0.5", "php": "~8.1.0 || ~8.2.0 || ~8.3.0", - "phpunit/php-code-coverage": "^10.1.3", - "phpunit/php-file-iterator": "^4.0.2", + "phpunit/php-code-coverage": "^10.1.7", + "phpunit/php-file-iterator": "^4.1.0", "phpunit/php-timer": "^6.0", - "phpunit/phpunit": "^10.3.2", + "phpunit/phpunit": "^10.4.0", "sebastian/environment": "^6.0.1", "symfony/console": "^6.3.4", "symfony/process": "^6.3.4" @@ -4861,8 +4959,8 @@ "doctrine/coding-standard": "^12.0.0", "ext-pcov": "*", "ext-posix": "*", - "infection/infection": "^0.27.0", - "phpstan/phpstan": "^1.10.32", + "infection/infection": "^0.27.3", + "phpstan/phpstan": "^1.10.37", "phpstan/phpstan-deprecation-rules": "^1.1.4", "phpstan/phpstan-phpunit": "^1.3.14", "phpstan/phpstan-strict-rules": "^1.5.1", @@ -4908,7 +5006,7 @@ ], "support": { "issues": "https://github.com/paratestphp/paratest/issues", - "source": "https://github.com/paratestphp/paratest/tree/v7.2.8" + "source": "https://github.com/paratestphp/paratest/tree/v7.2.9" }, "funding": [ { @@ -4920,7 +5018,7 @@ "type": "paypal" } ], - "time": "2023-10-04T13:38:04+00:00" + "time": "2023-10-06T07:53:04+00:00" }, { "name": "composer/pcre", @@ -6380,25 +6478,25 @@ }, { "name": "orchestra/testbench", - "version": "v8.12.2", + "version": "v8.13.0", "source": { "type": "git", "url": "https://github.com/orchestral/testbench.git", - "reference": "1f1bba4effb8199b712cc07fe0073d4f5727c119" + "reference": "b793195fa30517a89fd20b36b5d668324c5bbdbb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench/zipball/1f1bba4effb8199b712cc07fe0073d4f5727c119", - "reference": "1f1bba4effb8199b712cc07fe0073d4f5727c119", + "url": "https://api.github.com/repos/orchestral/testbench/zipball/b793195fa30517a89fd20b36b5d668324c5bbdbb", + "reference": "b793195fa30517a89fd20b36b5d668324c5bbdbb", "shasum": "" }, "require": { "composer-runtime-api": "^2.2", "fakerphp/faker": "^1.21", - "laravel/framework": ">=10.23.1 <10.27.0", + "laravel/framework": "^10.23.1", "mockery/mockery": "^1.5.1", - "orchestra/testbench-core": ">=8.12.0 <8.13.0", - "orchestra/workbench": "^0.4.0", + "orchestra/testbench-core": ">=8.13.0 <8.14.0", + "orchestra/workbench": "^0.4.0 || ^0.5.0", "php": "^8.1", "phpunit/phpunit": "^9.6 || ^10.1", "spatie/laravel-ray": "^1.32.4", @@ -6430,28 +6528,34 @@ ], "support": { "issues": "https://github.com/orchestral/testbench/issues", - "source": "https://github.com/orchestral/testbench/tree/v8.12.2" + "source": "https://github.com/orchestral/testbench/tree/v8.13.0" }, - "time": "2023-10-03T04:16:40+00:00" + "time": "2023-10-09T12:14:00+00:00" }, { "name": "orchestra/testbench-core", - "version": "v8.12.1", + "version": "v8.13.0", "source": { "type": "git", "url": "https://github.com/orchestral/testbench-core.git", - "reference": "9a7b63f9cd10dd15cf7c9d4aad2ccaa688465a1f" + "reference": "b03aa317d3c660dd63e4096580d7f713bc2cab15" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/9a7b63f9cd10dd15cf7c9d4aad2ccaa688465a1f", - "reference": "9a7b63f9cd10dd15cf7c9d4aad2ccaa688465a1f", + "url": "https://api.github.com/repos/orchestral/testbench-core/zipball/b03aa317d3c660dd63e4096580d7f713bc2cab15", + "reference": "b03aa317d3c660dd63e4096580d7f713bc2cab15", "shasum": "" }, "require": { "composer-runtime-api": "^2.2", "php": "^8.1" }, + "conflict": { + "brianium/paratest": "<6.4.0 || >=7.0.0 <7.1.4 || >=8.0.0", + "laravel/framework": "<10.23.1 || >=11.0.0", + "nunomaduro/collision": "<6.4.0 || >=7.0.0 <7.4.0 || >=8.0.0", + "phpunit/phpunit": "<9.6.0 || >=10.5.0" + }, "require-dev": { "fakerphp/faker": "^1.21", "laravel/framework": "^10.23", @@ -6465,7 +6569,7 @@ "vlucas/phpdotenv": "^5.4.1" }, "suggest": { - "brianium/paratest": "Allow using parallel tresting (^6.4 || ^7.1.4).", + "brianium/paratest": "Allow using parallel testing (^6.4 || ^7.1.4).", "fakerphp/faker": "Allow using Faker for testing (^1.21).", "laravel/framework": "Required for testing (^10.23).", "mockery/mockery": "Allow using Mockery for testing (^1.5.1).", @@ -6513,20 +6617,20 @@ "issues": "https://github.com/orchestral/testbench/issues", "source": "https://github.com/orchestral/testbench-core" }, - "time": "2023-09-26T12:50:24+00:00" + "time": "2023-10-09T11:41:27+00:00" }, { "name": "orchestra/workbench", - "version": "v0.4.1", + "version": "v0.5.0", "source": { "type": "git", "url": "https://github.com/orchestral/workbench.git", - "reference": "21acf1015ac48e36cb468bffd161115689958782" + "reference": "01175d82fd80a6589ffaa9a861100a64c500b259" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/orchestral/workbench/zipball/21acf1015ac48e36cb468bffd161115689958782", - "reference": "21acf1015ac48e36cb468bffd161115689958782", + "url": "https://api.github.com/repos/orchestral/workbench/zipball/01175d82fd80a6589ffaa9a861100a64c500b259", + "reference": "01175d82fd80a6589ffaa9a861100a64c500b259", "shasum": "" }, "require": { @@ -6551,7 +6655,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "0.4.x-dev" + "dev-master": "0.5.x-dev" } }, "autoload": { @@ -6578,41 +6682,41 @@ ], "support": { "issues": "https://github.com/orchestral/workbench/issues", - "source": "https://github.com/orchestral/workbench/tree/v0.4.1" + "source": "https://github.com/orchestral/workbench/tree/v0.5.0" }, - "time": "2023-09-26T13:04:34+00:00" + "time": "2023-10-06T12:50:40+00:00" }, { "name": "pestphp/pest", - "version": "v2.20.0", + "version": "v2.21.0", "source": { "type": "git", "url": "https://github.com/pestphp/pest.git", - "reference": "a8b785f69e44ae3f902cbf08fe6b79359ba46945" + "reference": "2ffafd445d42c8b7b7e1874bde1c29945767a49d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pestphp/pest/zipball/a8b785f69e44ae3f902cbf08fe6b79359ba46945", - "reference": "a8b785f69e44ae3f902cbf08fe6b79359ba46945", + "url": "https://api.github.com/repos/pestphp/pest/zipball/2ffafd445d42c8b7b7e1874bde1c29945767a49d", + "reference": "2ffafd445d42c8b7b7e1874bde1c29945767a49d", "shasum": "" }, "require": { - "brianium/paratest": "^7.2.7", + "brianium/paratest": "^7.2.9", "nunomaduro/collision": "^7.9.0", "nunomaduro/termwind": "^1.15.1", "pestphp/pest-plugin": "^2.1.1", "pestphp/pest-plugin-arch": "^2.3.3", "php": "^8.1.0", - "phpunit/phpunit": "^10.3.5" + "phpunit/phpunit": "^10.4.0" }, "conflict": { - "phpunit/phpunit": ">10.3.5", + "phpunit/phpunit": ">10.4.0", "sebastian/exporter": "<5.1.0", "webmozart/assert": "<1.11.0" }, "require-dev": { "pestphp/pest-dev-tools": "^2.16.0", - "pestphp/pest-plugin-type-coverage": "^2.2.0", + "pestphp/pest-plugin-type-coverage": "^2.4.0", "symfony/process": "^6.3.4" }, "bin": [ @@ -6671,7 +6775,7 @@ ], "support": { "issues": "https://github.com/pestphp/pest/issues", - "source": "https://github.com/pestphp/pest/tree/v2.20.0" + "source": "https://github.com/pestphp/pest/tree/v2.21.0" }, "funding": [ { @@ -6683,7 +6787,7 @@ "type": "github" } ], - "time": "2023-09-29T18:05:52+00:00" + "time": "2023-10-06T12:33:39+00:00" }, { "name": "pestphp/pest-plugin", @@ -7234,16 +7338,16 @@ }, { "name": "phpstan/phpstan", - "version": "1.10.37", + "version": "1.10.38", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "058ba07e92f744d4dcf6061ae75283d0c6456f2e" + "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/058ba07e92f744d4dcf6061ae75283d0c6456f2e", - "reference": "058ba07e92f744d4dcf6061ae75283d0c6456f2e", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/5302bb402c57f00fb3c2c015bac86e0827e4b691", + "reference": "5302bb402c57f00fb3c2c015bac86e0827e4b691", "shasum": "" }, "require": { @@ -7292,7 +7396,7 @@ "type": "tidelift" } ], - "time": "2023-10-02T16:18:37+00:00" + "time": "2023-10-06T14:19:14+00:00" }, { "name": "phpunit/php-code-coverage", @@ -7617,16 +7721,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.3.5", + "version": "10.4.0", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503" + "reference": "9784e877e3700de37475545bdbdce8383ff53d25" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/747c3b2038f1139e3dcd9886a3f5a948648b7503", - "reference": "747c3b2038f1139e3dcd9886a3f5a948648b7503", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/9784e877e3700de37475545bdbdce8383ff53d25", + "reference": "9784e877e3700de37475545bdbdce8383ff53d25", "shasum": "" }, "require": { @@ -7666,7 +7770,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "10.3-dev" + "dev-main": "10.4-dev" } }, "autoload": { @@ -7698,7 +7802,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.3.5" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.4.0" }, "funding": [ { @@ -7714,7 +7818,7 @@ "type": "tidelift" } ], - "time": "2023-09-19T05:42:37+00:00" + "time": "2023-10-06T03:41:22+00:00" }, { "name": "pimple/pimple", diff --git a/core b/core new file mode 160000 index 0000000..26673a1 --- /dev/null +++ b/core @@ -0,0 +1 @@ +Subproject commit 26673a1766f41b48f6628cde9f36d575835c3d12 diff --git a/phpunit.xml b/phpunit.xml index da97a05..5cced19 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -8,14 +8,6 @@ ./tests/Integration - - - ./tests/Feature - - - - ./tests/Unit - diff --git a/skeleton/bootstrap/cache/.gitkeep b/skeleton/bootstrap/cache/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/skeleton/storage/framework/views/.gitkeep b/skeleton/storage/framework/views/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/skeleton/storage/logs/.gitkeep b/skeleton/storage/logs/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/Commands/Concerns/PromptForOptionWhenMissing.php b/src/Commands/Concerns/PromptForOptionWhenMissing.php deleted file mode 100644 index f1e0949..0000000 --- a/src/Commands/Concerns/PromptForOptionWhenMissing.php +++ /dev/null @@ -1,22 +0,0 @@ -option($option); - - if ($value !== null) { - return $value; - } - - return confirm( - label: $label, - default: $default - ); - } -} diff --git a/src/Commands/Install.php b/src/Commands/Install.php deleted file mode 100644 index f12d6f4..0000000 --- a/src/Commands/Install.php +++ /dev/null @@ -1,207 +0,0 @@ -integrations = $integrations; - } - - public function handle() - { - if ($this->option('quickly')) { - self::$SLEEP_BETWEEN_STEPS = 0; - } - - // Prompt for input if missing - $publishWorkflows = $this->promptForOptionWhenMissing( - option: 'publish-workflows', - label: 'Would you also like to publish CI Workflow files? (recommended)' - ); - - // Before hooks - foreach ($this->integrations->beforeInstall() as $callback) { - $callback($this); - } - - $this->installComposerDependencies(); - $this->installNpmDependencies(); - $this->publishConfigs(); - $this->updateGitignore(); - $this->installDusterConfiguration(); - $this->installComposerScripts(); - - if ($publishWorkflows) { - $this->publishWorkflows(); - } - - // After hooks - foreach ($this->integrations->afterInstall() as $callback) { - $callback($this); - } - } - - protected function installComposerDependencies() - { - spin( - function () { - // composer install - $commands = implode(' ', $this->integrations->composerRequire()); - - Process::path(base_path()) - ->run("composer require {$commands} --no-interaction") - ->throw(); - - // composer install - $commands = implode(' ', $this->integrations->composerRequireDev()); - - Process::path(base_path()) - ->run("composer require {$commands} --dev --no-interaction") - ->throw(); - }, - 'Installing Composer dependencies' - ); - } - - protected function installNpmDependencies() - { - spin( - function () { - // Npm install - $commands = implode(' ', $this->integrations->npmInstall()); - - Process::path(base_path()) - ->run("npm install {$commands}") - ->throw(); - - // Npm install dev - $commands = implode(' ', $this->integrations->npmInstallDev()); - - Process::path(base_path()) - ->run("npm install {$commands} --save-dev") - ->throw(); - }, - 'Installing NPM dependencies' - ); - } - - protected function publishConfigs() - { - spin(function () { - sleep(self::$SLEEP_BETWEEN_STEPS); // Only for 💅 - - $this->callSilently('vendor:publish', [ - '--tag' => 'workspace-3rd-party-configs', - '--force' => true, - ]); - }, 'Publishing 3rd party configs'); - } - - protected function updateGitignore() - { - spin(function () { - sleep(self::$SLEEP_BETWEEN_STEPS); // Only for 💅 - - $this->removeFromGitignore( - $this->integrations->removeFromGitignore() - ); - - $this->addToGitignore( - $this->integrations->addToGitignore() - ); - }, 'Updating .gitignore'); - } - - protected function installDusterConfiguration() - { - spin(function () { - sleep(self::$SLEEP_BETWEEN_STEPS); // Only for 💅 - - // Note we assume duster.json is present since the Duster integration is mandatory - $path = base_path('duster.json'); - $config = json_decode(file_get_contents($path)); - $linters = $this->integrations->dusterLintConfig(); - $fixers = $this->integrations->dusterFixConfig(); - - foreach ($linters as $name => $integration) { - data_set($config, "scripts.lint.{$name}", $integration); - } - - foreach ($fixers as $name => $integration) { - data_set($config, "scripts.fix.{$name}", $integration, overwrite: true); - } - - // Persist - file_put_contents( - $path, - json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL - ); - }, 'Installing integrations in Duster config'); - } - - protected function installComposerScripts() - { - spin(function () { - sleep(self::$SLEEP_BETWEEN_STEPS); // Only for 💅 - - $composer = json_decode(file_get_contents(base_path('composer.json'))); - $workspaceScripts = $this->integrations->composerScripts(); - $composerScripts = $composer->scripts ?? (object) []; - - throw_unless($composer, RuntimeException::class, "composer.json couldn't be parsed"); - - // The mergeConfigsRecursively method might be a bit prone to break - $merged = $this->mergeConfigsRecursively((array) $composerScripts, (array) $workspaceScripts); - - data_set($composer, 'scripts', $merged, overwrite: true); - - file_put_contents( - base_path('composer.json'), - json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL - ); - }, 'Installing Composer script aliases'); - } - - protected function publishWorkflows() - { - spin(function () { - sleep(self::$SLEEP_BETWEEN_STEPS); // Only for 💅 - - $this->removeFromGitignore([ - '.github', - ]); - - $this->callSilently('vendor:publish', [ - '--tag' => 'workspace-workflows', - '--force' => true, - ]); - }, 'Publishing workflow files'); - } -} diff --git a/src/Commands/Integrate.php b/src/Commands/Integrate.php deleted file mode 100644 index 0436671..0000000 --- a/src/Commands/Integrate.php +++ /dev/null @@ -1,170 +0,0 @@ -integrations = $integrations; - } - - public function handle() - { - if ($this->option('quickly')) { - self::$SLEEP_BETWEEN_STEPS = 0; - } - - $editors = $this->promptForEditorIfMissing(); - - // Before hooks - foreach ($this->integrations->beforeIntegration() as $callback) { - $callback($this); - } - - if (in_array('vscode', (array) $editors)) { - $this->integrateVSCode(); - } - - if (in_array('phpstorm', (array) $editors)) { - $this->integratePhpStorm(); - } - - // After hooks - foreach ($this->integrations->afterIntegration() as $callback) { - $callback($this); - } - - // Show informational messages after integration - if (in_array('vscode', (array) $editors)) { - $this->postInstallInfoVSCode(); - } - if (in_array('phpstorm', (array) $editors)) { - $this->postInstallInfoPhpStorm(); - } - } - - /* - |-------------------------------------------------------------------------- - | Visual Studio Code - |-------------------------------------------------------------------------- - */ - protected function integrateVSCode() - { - spin(function () { - $this->removeFromGitignore('.vscode'); - $this->publishVSCodeWorkspaceConfig(); - - sleep(self::$SLEEP_BETWEEN_STEPS); // Only for 💅 - }, 'Integrating Visual Studio Code in your project'); - } - - protected function publishVSCodeWorkspaceConfig() - { - // Publish extensions.json - $extensions = (object) [ - 'recommendations' => $this->integrations->provideVscodeRecommendedPlugins(), - 'unwantedRecommendations' => $this->integrations->provideVscodeAvoidPlugins(), - ]; - - $vscodeDir = base_path('.vscode'); - if (! file_exists($vscodeDir)) { - mkdir($vscodeDir); - } - touch("{$vscodeDir}/extensions.json"); - - file_put_contents( - base_path('.vscode/extensions.json'), - json_encode($extensions, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL - ); - - // Publish settings.json - file_put_contents( - base_path('.vscode/settings.json'), - json_encode($this->integrations->provideVscodeWorkspaceConfig(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL - ); - } - - protected function postInstallInfoVSCode() - { - $this->outputComponents()->info('VSCode workspace environment configured!'); - info('Please reload VSCode & install the workspace recommended extensions when prompted'); - info("If the prompt doesn't appear; Open the command pallette [CMD + Shift + P] and select 'Show Recommended Extensions'"); - } - - /* - |-------------------------------------------------------------------------- - | PhpStorm - |-------------------------------------------------------------------------- - */ - protected function integratePhpStorm() - { - spin(function () { - $this->removeFromGitignore('.idea'); - $this->publishPhpStormWorkspaceConfig(); - - sleep(self::$SLEEP_BETWEEN_STEPS); // Only for 💅 - }, 'Integrating PhpStorm in your project'); - } - - protected function publishPhpStormWorkspaceConfig() - { - // mkdir(base_path('.vscode')); - // touch(base_path('.vscode/extensions.json')); - } - - protected function postInstallInfoPhpStorm() - { - warning('TODO: PhpStorm integration pending...'); - - // $this->outputComponents()->info('PhpStorm workspace environment configured!'); - // info('Please reload PhpStorm & install the workspace recommended & required plugins when prompted'); - } - - /* - |-------------------------------------------------------------------------- - | Support - |-------------------------------------------------------------------------- - */ - private function promptForEditorIfMissing() - { - $editor = $this->option('editor'); - - if (in_array($editor, ['vscode', 'phpstorm'])) { - return $editor; - } - - // Option not set or invalid, prompt for input - return multiselect( - 'What IDE are you using?', - [ - 'vscode' => 'Visual Studio Code', - 'phpstorm' => 'PhpStorm', - ], - hint: 'Select one or both', - required: true, - ); - } -} diff --git a/src/Commands/Update.php b/src/Commands/Update.php deleted file mode 100644 index 186c5bb..0000000 --- a/src/Commands/Update.php +++ /dev/null @@ -1,143 +0,0 @@ -integrations = $integrations; - } - - public function handle() - { - if (! $this->promptToContinueWhenWorkspaceHasUncommittedFiles()) { - return static::FAILURE; - } - - // Prompt for input if missing - $publishWorkflows = $this->promptForOptionWhenMissing( - option: 'publish-workflows', - label: 'Would you also like to update CI Workflow files?' - ); - - // Before hooks - foreach ($this->integrations->beforeUpdate() as $callback) { - $callback($this); - } - - $this->updateWorkspace(); - $this->updateComposerDependencies(); - $this->updateNpmDependencies(); - $this->runWorkspaceInstall($publishWorkflows); - - // After hooks - foreach ($this->integrations->afterUpdate() as $callback) { - $callback($this); - } - - // Nice Laravel-style comment for all you geeks out there - info(<<<'TEXT' - /* - |----------------------------------------------------------------------------- - | Did you know? - |----------------------------------------------------------------------------- - | - | Workspace is highly extendable, allowing for sharing of custom integrations - | across various projects. This ensures a consistent setup for linting, - | fixing, static analysis, and editor configuration for your team. - | - | https://github.com/media-code/workspace/docs/portable-workspace - */ - TEXT); - - warning('Successfully updated Workspace!'); - note('Please manually review all changes'); - // TODO: Notify this command only bumps workspace package by minor version. Bumping a whole version requires manual composer update - } - - protected function promptToContinueWhenWorkspaceHasUncommittedFiles() - { - $result = Process::path(base_path()) - ->run('git status --porcelain') - ->throw(); - - // No changes in tracked files - if ($result->output() === '') { - return true; - } - - warning('Workspace detected untracked changes in your project'); - note('We recommend stashing or committing your work before updating your workspace' . PHP_EOL . 'This way it\'s easier to review any upsteam configuration changes'); - - return confirm( - label: 'Do you want to continue?', - default: false - ); - } - - protected function updateWorkspace() - { - spin( - fn () => Process::path(base_path()) - ->run('composer update gedachtegoed/workspace --no-interaction') - ->throw(), - 'Updating Workspace' - ); - } - - protected function updateNpmDependencies() - { - $commands = implode(' ', $this->integrations->npmUpdate()); - - spin( - fn () => Process::path(base_path()) - ->run("npm update {$commands}") - ->throw(), - 'Updating NPM dependencies' - ); - } - - protected function updateComposerDependencies() - { - $commands = implode(' ', $this->integrations->composerUpdate()); - - spin( - fn () => Process::path(base_path()) - ->run("composer update {$commands}") - ->throw(), - 'Updating Composer dependencies' - ); - } - - protected function runWorkspaceInstall(bool $publishWorkflows) - { - spin( - fn () => $this->callSilently('workspace:install', [ - '--publish-workflows' => $publishWorkflows, - '--quickly' => true, - ]), 'Running workspace:install' - ); - } -} diff --git a/src/Core/Aggregator.php b/src/Core/Aggregator.php deleted file mode 100644 index 37f500c..0000000 --- a/src/Core/Aggregator.php +++ /dev/null @@ -1,171 +0,0 @@ - */ - protected readonly Collection $integrations; - - /** @param array $integrations */ - public function __construct(array $integrations) - { - $defaultIntegrations = $this->resolve(static::DEFAULT_INTEGRATIONS); - $configuredIntegrations = $this->resolve($integrations); - - $this->integrations = $defaultIntegrations->merge($configuredIntegrations); - - $this->registerIntegrationPublishGroups(); - } - - /** - * Static constructor - * - * @param array $integrations - */ - public static function make(array $integrations) - { - return new self($integrations); - } - - /** - * Returns all resolved integrations - */ - public function integrations(): Collection - { - return $this->integrations; - } - - /** - * Resolves Integrations by a array of their respective Builder classes - * - * @param array $integrations Array of fully qualified classnames - * @return Collection - */ - private function resolve(array $integrations): Collection - { - return collect($integrations)->map(function (string|Builder $implementation) { - // Check if the given implementation resolves to a Builder implementation - throw_unless( - $implementation instanceof Builder || is_subclass_of($implementation, Builder::class), - InvalidArgumentException::class, - 'Workspace configuration must be of type Workspace\\Core\\Builder' - ); - - // Either resolve classname from container or use inlined builder instance from config - $builder = $implementation instanceof Builder - ? $implementation - : resolve($implementation); - - // If the implementation has an invoke method, invoke that automatically - method_exists($builder, '__invoke') - ? call_user_func($builder) - : null; - - return $builder->getIntegration(); - }); - } - - private function registerIntegrationPublishGroups() - { - // @phpstan-ignore-next-line - app()->getProvider(ServiceProvider::class)->publishes( - $this->publishesConfigs(), - 'workspace-3rd-party-configs' - ); - - // @phpstan-ignore-next-line - app()->getProvider(ServiceProvider::class)->publishes( - $this->publishesWorkflows(), - 'workspace-workflows' - ); - } - - /** - * Forwards method calls to collect integration properties. - * Please see class PHPDoc method hints for a list of methods this provides. - * - * @param string $name property of Integration to aggregate - */ - public function __call(string $name, ?array $arguments): array - { - throw_unless( - property_exists(Integration::class, $name), - UndefinedMethodError::class, - ); - - return $this->integrations->flatMap->{$name}->toArray(); - } - - /** - * Returns aggregated composer script definition - * Not proxied via magic __call because configs need to be merged recursively - */ - public function composerScripts(): array - { - return $this->integrations->reduce( - fn ($carry, $integration) => $this->mergeConfigsRecursively($carry, $integration->composerScripts), - [] - ); - } -} diff --git a/src/Core/Builder.php b/src/Core/Builder.php deleted file mode 100644 index e115ff0..0000000 --- a/src/Core/Builder.php +++ /dev/null @@ -1,288 +0,0 @@ -integration = new Integration; - } - - public function getIntegration(): Integration - { - return $this->integration; - } - - //-------------------------------------------------------------------------- - // Configs and workflows - //-------------------------------------------------------------------------- - - public function publishesConfigs(array $configMap): self - { - // Make sure source path is relative to the Integration path - $configMap = Arr::mapWithKeys( - $configMap, fn ($to, $from) => [$this->integrationPath($from) => base_path($to)] - ); - - foreach ($configMap as $from => $to) { - throw_unless(file_exists($from), new ConfigNotFoundException($from)); - } - - $this->integration->publishesConfigs = $this->integration->publishesConfigs + $configMap; - - return $this; - } - - public function publishesWorkflows(array $workflowMap): self - { - // Make sure source path is relative to the Integration path - $workflowMap = Arr::mapWithKeys( - $workflowMap, fn ($to, $from) => [$this->integrationPath($from) => base_path($to)] - ); - - foreach ($workflowMap as $from => $to) { - throw_unless(file_exists($from), new WorkflowNotFoundException($from)); - } - - $this->integration->publishesWorkflows = $this->integration->publishesWorkflows + $workflowMap; - - return $this; - } - - //-------------------------------------------------------------------------- - // Duster - //-------------------------------------------------------------------------- - - public function provideDusterLintConfig(array $config): self - { - $this->integration->dusterLintConfig = $this->integration->dusterLintConfig + $config; - - return $this; - } - - public function provideDusterFixConfig(array $config): self - { - $this->integration->dusterFixConfig = $this->integration->dusterFixConfig + $config; - - return $this; - } - - //-------------------------------------------------------------------------- - // Composer - //-------------------------------------------------------------------------- - - public function composerScripts(array|string $scripts): self - { - $this->integration->composerScripts = $this->integration->composerScripts + (array) $scripts; - - return $this; - } - - public function composerRequire(array|string $dependencies): self - { - $this->integration->composerRequire = $this->integration->composerRequire + (array) $dependencies; - - return $this; - } - - public function composerRequireDev(array|string $dependencies): self - { - $this->integration->composerRequireDev = $this->integration->composerRequireDev + (array) $dependencies; - - return $this; - } - - public function composerUpdate(array|string $dependencies): self - { - $this->integration->composerUpdate = $this->integration->composerUpdate + (array) $dependencies; - - return $this; - } - - //-------------------------------------------------------------------------- - // NPM - //-------------------------------------------------------------------------- - - public function npmInstall(array|string $dependencies): self - { - $this->integration->npmInstall = $this->integration->npmInstall + (array) $dependencies; - - return $this; - } - - public function npmInstallDev(array|string $dependencies): self - { - $this->integration->npmInstallDev = $this->integration->npmInstallDev + (array) $dependencies; - - return $this; - } - - public function npmUpdate(array|string $dependencies): self - { - $this->integration->npmUpdate = $this->integration->npmUpdate + (array) $dependencies; - - return $this; - } - - //-------------------------------------------------------------------------- - // Gitignore - //-------------------------------------------------------------------------- - - public function addToGitignore(string|array $line): self - { - $this->integration->addToGitignore = $this->integration->addToGitignore + (array) $line; - - return $this; - } - - public function removeFromGitignore(string|array $line): self - { - $this->integration->removeFromGitignore = $this->integration->removeFromGitignore + (array) $line; - - return $this; - } - - //-------------------------------------------------------------------------- - // Visual Studio Code integrations - //-------------------------------------------------------------------------- - - public function provideVscodeWorkspaceConfig(string|array $line): self - { - $this->integration->provideVscodeWorkspaceConfig = $this->integration->provideVscodeWorkspaceConfig + (array) $line; - - return $this; - } - - public function provideVscodeRecommendedPlugins(string|array $plugins): self - { - $this->integration->provideVscodeRecommendedPlugins = $this->integration->provideVscodeRecommendedPlugins + (array) $plugins; - - return $this; - } - - public function provideVscodeAvoidPlugins(string|array $plugins): self - { - $this->integration->provideVscodeAvoidPlugins = $this->integration->provideVscodeAvoidPlugins + (array) $plugins; - - return $this; - } - - //-------------------------------------------------------------------------- - // PhpStorm integrations - //-------------------------------------------------------------------------- - - public function providePhpStormWorkspaceConfig(string|array $line): self - { - $this->integration->providePhpStormWorkspaceConfig = $this->integration->providePhpStormWorkspaceConfig + (array) $line; - - return $this; - } - - public function providePhpStormRequiredPlugins(string|array $plugins): self - { - $this->integration->providePhpStormRequiredPlugins = $this->integration->providePhpStormRequiredPlugins + (array) $plugins; - - return $this; - } - - public function providePhpStormSuggestedPlugins(string|array $plugins): self - { - $this->integration->providePhpStormSuggestedPlugins = $this->integration->providePhpStormSuggestedPlugins + (array) $plugins; - - return $this; - } - - //-------------------------------------------------------------------------- - // Lifecycle Hooks - //-------------------------------------------------------------------------- - - /** @param callable(Install $command):void $callback */ - public function beforeInstall(callable $callback): self // @phpstan-ignore argument.type - { - $this->integration->beforeInstall[] = $callback; - - return $this; - } - - /** @param callable(Install $command):void $callback */ - public function afterInstall(callable $callback): self - { - $this->integration->afterInstall[] = $callback; - - return $this; - } - - /** @param callable(Update $command):void $callback */ - public function beforeUpdate(callable $callback): self - { - $this->integration->beforeUpdate[] = $callback; - - return $this; - } - - /** @param callable(Update $command):void $callback */ - public function afterUpdate(callable $callback): self - { - $this->integration->afterUpdate[] = $callback; - - return $this; - } - - /** @param callable(Integration $command):void $callback */ - public function beforeIntegration(callable $callback): self - { - $this->integration->beforeIntegration[] = $callback; - - return $this; - } - - /** @param callable(Integration $command):void $callback */ - public function afterIntegration(callable $callback): self - { - $this->integration->afterIntegration[] = $callback; - - return $this; - } - - //-------------------------------------------------------------------------- - // Support - //-------------------------------------------------------------------------- - - // FIXME: Does not work with inlined integrations - private function integrationPath(string $append): string - { - // Is used inline. Assume absolute path is used - if ($this::class === self::class) { - return $append; - } - - // Normalize the append arg - $file = str($append) - ->trim(DIRECTORY_SEPARATOR) - ->prepend(DIRECTORY_SEPARATOR) - ->toString(); - - // Make it relative to the integration path - $integrationClass = new ReflectionClass(get_class($this)); - - return str($integrationClass->getFileName()) - ->beforeLast(DIRECTORY_SEPARATOR) // Strip filename - ->append($file) - ->toString(); - } -} diff --git a/src/Core/Concerns/InteractsWithDirectories.php b/src/Core/Concerns/InteractsWithDirectories.php deleted file mode 100644 index 5385fab..0000000 --- a/src/Core/Concerns/InteractsWithDirectories.php +++ /dev/null @@ -1,52 +0,0 @@ -clearDirectory($destination); - - // Copy source contents - $iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS), - RecursiveIteratorIterator::SELF_FIRST - ); - - foreach ($iterator as $item) { - if ($item->isDir()) { - mkdir($destination . DIRECTORY_SEPARATOR . $iterator->getSubPathname()); - - continue; - } - copy($item, $destination . DIRECTORY_SEPARATOR . $iterator->getSubPathname()); - } - } - - public function clearDirectory($dir) - { - $iterator = new RecursiveIteratorIterator( - new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS), - RecursiveIteratorIterator::CHILD_FIRST - ); - - foreach ($iterator as $file) { - if ($file->isLink()) { - continue; - } - - if ($file->isDir()) { - rmdir($file->getRealPath()); - - continue; - } - - unlink($file->getRealPath()); - } - } -} diff --git a/src/Core/Concerns/MergesConfigsRecursively.php b/src/Core/Concerns/MergesConfigsRecursively.php deleted file mode 100644 index b8a2362..0000000 --- a/src/Core/Concerns/MergesConfigsRecursively.php +++ /dev/null @@ -1,26 +0,0 @@ - $value) { - if (is_array($value) && isset($left[$key]) && is_array($left[$key])) { - $merged = array_values(array_unique(array_merge($left[$key], $value))); - $left[$key] = $this->mergeConfigsRecursively($left[$key], $merged); - } else { - $left[$key] = $value; - } - } - - return $left; - } -} diff --git a/src/Core/Concerns/UpdatesGitignore.php b/src/Core/Concerns/UpdatesGitignore.php deleted file mode 100644 index 8b72db5..0000000 --- a/src/Core/Concerns/UpdatesGitignore.php +++ /dev/null @@ -1,53 +0,0 @@ -removeFromGitignore($line); - - $gitignore = file_exists($path) - ? file_get_contents($path) - : ''; - - $gitignore = $gitignore . PHP_EOL . $line; - - file_put_contents($path, trim($gitignore) . PHP_EOL); - } - } - - public function removeFromGitignore(array|string $lines, string $path = null) - { - $lines = (array) $lines; - - if (empty($lines)) { - return; - } - - $path = $path - ? $path . DIRECTORY_SEPARATOR . '.gitignore' - : base_path('.gitignore'); - - if (! file_exists($path)) { - return; - } - - $gitignore = file_get_contents($path); - - $implodedLines = implode('|', $lines); - $gitignore = preg_replace("/^.*(?:{$implodedLines}).*$(?:\r\n|\n)?/m", '', $gitignore); - - // Persist - file_put_contents($path, trim($gitignore) . PHP_EOL); - } -} diff --git a/src/Core/Integration.php b/src/Core/Integration.php deleted file mode 100644 index fc71cd5..0000000 --- a/src/Core/Integration.php +++ /dev/null @@ -1,81 +0,0 @@ - */ - public array $beforeInstall = []; - - /** @var array */ - public array $afterInstall = []; - - /** @var array */ - public array $beforeUpdate = []; - - /** @var array */ - public array $afterUpdate = []; - - /** @var array */ - public array $beforeIntegration = []; - - /** @var array */ - public array $afterIntegration = []; -} diff --git a/src/Exceptions/ConfigNotFoundException.php b/src/Exceptions/ConfigNotFoundException.php deleted file mode 100644 index f139791..0000000 --- a/src/Exceptions/ConfigNotFoundException.php +++ /dev/null @@ -1,13 +0,0 @@ -composerRequireDev('tightenco/duster') - ->composerUpdate('tightenco/duster') - ->publishesConfigs([ - 'duster.json' => 'duster.json', - ]); - } -} diff --git a/src/Integrations/Duster/duster.json b/src/Integrations/Duster/duster.json deleted file mode 100644 index 10061e9..0000000 --- a/src/Integrations/Duster/duster.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "scripts": { - "lint": { - }, - "fix": { - } - }, - "processTimeout": 120 -} diff --git a/src/Integrations/IDEHelper/IDEHelper.php b/src/Integrations/IDEHelper/IDEHelper.php index 740ed76..f0cc835 100644 --- a/src/Integrations/IDEHelper/IDEHelper.php +++ b/src/Integrations/IDEHelper/IDEHelper.php @@ -2,8 +2,8 @@ namespace Gedachtegoed\Workspace\Integrations\IDEHelper; -use Gedachtegoed\Workspace\Commands\Install; use Gedachtegoed\Workspace\Core\Builder; +use Gedachtegoed\Workspace\Core\Commands\Install; use Illuminate\Support\Facades\Process; use function Laravel\Prompts\spin; diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 1336e22..5fcb3d2 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -2,77 +2,23 @@ namespace Gedachtegoed\Workspace; -use Gedachtegoed\Workspace\Core\Aggregator; -use Illuminate\Contracts\Support\DeferrableProvider; use Illuminate\Support\ServiceProvider as BaseServiceProvider; -class ServiceProvider extends BaseServiceProvider implements DeferrableProvider +class ServiceProvider extends BaseServiceProvider { - public function provides(): array - { - return [Aggregator::class]; - } - public function boot(): void { if (! $this->app->environment(['local', 'testing'])) { - return; + return; // @codeCoverageIgnore } - $this->app->bind( - Aggregator::class, - fn () => Aggregator::make(config('workspace-integrations')) - ); - $this->publishes([ __DIR__ . '/../config/workspace-integrations.php' => base_path('config/workspace-integrations.php'), ], 'workspace-config'); - - $this->registerCommandAliasses(); - - // TODO: Disabled for now. Not sure about the added benefit - // $this->registerIntegrationConfig(); } public function register() { $this->mergeConfigFrom(__DIR__ . '/../config/workspace-integrations.php', 'workspace-integrations'); } - - protected function registerCommandAliasses() - { - if ($this->app->runningInConsole()) { - $this->commands([ - Commands\Integrate::class, - Commands\Install::class, - Commands\Update::class, - ]); - } - } - - /** - * Only used to provide defaults when running vendor:publish outside of the workspace command - * The Aggregator class modifies this during runtime to provide up to date config files - * for your configured Integrations - */ - protected function registerIntegrationConfig() - { - $integrations = $this->app->make(Aggregator::class); - - $this->publishes( - $integrations->publishesConfigs(), - 'workspace-3rd-party-configs' - ); - - $this->publishes( - $integrations->publishesWorkflows(), - 'workspace-workflows' - ); - } - - /** Makes protected methd on parent class accessible so we can register config publishing on the fly */ - public function publishes(array $paths, $groups = null) - { - parent::publishes($paths, $groups); - } } diff --git a/testbench.yaml b/testbench.yaml index 768e7fc..63ea2d4 100644 --- a/testbench.yaml +++ b/testbench.yaml @@ -1,18 +1,3 @@ providers: - Gedachtegoed\Workspace\ServiceProvider - -laravel: ./skeleton -# purge: -# directories: -# - .vscode -# - .idea -# files: -# - .gitignore -# - .editorconfig -# - .php-cs-fixer.dist.php -# - .phpcs.xml.dist -# - .prettierrc.json -# - duster.json -# - phpstan.neon -# - pint.json -# - tlint.json + - Gedachtegoed\Workspace\Core\ServiceProvider diff --git a/tests/Feature/InstallCommandTest.php b/tests/Feature/InstallCommandTest.php deleted file mode 100644 index 04d746b..0000000 --- a/tests/Feature/InstallCommandTest.php +++ /dev/null @@ -1,218 +0,0 @@ - pugreSkeleton()); -beforeEach(fn () => Process::fake()); -afterAll(fn () => pugreSkeleton()); - -//-------------------------------------------------------------------------- -// Package managers -//-------------------------------------------------------------------------- -it('installs composer dependencies', function () { - register( - Builder::make()->composerRequire('foo/bar:^2'), - Builder::make()->composerRequire('bar/baz'), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - $dependencies = implode(' ', resolve(Aggregator::class)->composerRequire()); - Process::assertRan("composer require {$dependencies} --no-interaction"); -}); - -it('installs composer dev dependencies', function () { - register( - Builder::make()->composerRequireDev('foo/bar:^2'), - Builder::make()->composerRequireDev('bar/baz'), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - $dependencies = implode(' ', resolve(Aggregator::class)->composerRequireDev()); - Process::assertRan("composer require {$dependencies} --dev --no-interaction"); -}); - -it('installs npm dependencies', function () { - register( - Builder::make()->npmInstall('foo/bar:^2'), - Builder::make()->npmInstall('bar/baz'), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - $dependencies = implode(' ', resolve(Aggregator::class)->npmInstall()); - Process::assertRan("npm install {$dependencies}"); -}); - -it('installs npm dev dependencies', function () { - register( - Builder::make()->npmInstallDev('foo/bar:^2'), - Builder::make()->npmInstallDev('bar/baz'), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - $dependencies = implode(' ', resolve(Aggregator::class)->npmInstallDev()); - Process::assertRan("npm install {$dependencies} --save-dev"); -}); - -it('installs composer scripts', function () { - expectFileContents('composer.json')->json()->scripts->toBeEmpty(); - - register( - Builder::make()->composerScripts(['foo' => './vendor/bin some-command --with-flags']), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - expectFileContents('composer.json') - ->json() - ->scripts - ->foo->toBe('./vendor/bin some-command --with-flags'); -}); - -it('merges nested composer scripts', function () { - expectFileContents('composer.json')->json()->scripts->toBeEmpty(); - - register( - Builder::make()->composerScripts(['some-alias' => 'some-command --with-flags']), - Builder::make()->composerScripts(['post-update-cmd' => ['some-command']]), - Builder::make()->composerScripts(['post-update-cmd' => ['some-other-command']]), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - expectFileContents('composer.json') - ->json() - ->scripts - ->toMatchArray([ - 'some-alias' => 'some-command --with-flags', - 'post-update-cmd' => [ - 'some-command', - 'some-other-command', - ], - ]); -}); - -//-------------------------------------------------------------------------- -// Updates gitignore -//-------------------------------------------------------------------------- -it('adds lines to gitignore', function () { - expectFileExists('.gitignore')->toBeFalse(); - - register( - Builder::make()->addToGitignore('foobar') - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - expectFileContents('.gitignore')->toContain('foobar'); -}); - -it('adds lines to gitignore only once when line already present', function () { - expectFileExists('.gitignore')->toBeFalse(); - - register( - Builder::make()->addToGitignore('foobar'), - Builder::make()->addToGitignore('foobar') - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - $gitignore = file_get_contents(base_path('.gitignore')); - expect(substr_count($gitignore, 'foobar'))->toBe(1); -}); - -it('removes commented lines from gitignore by regex', function () { - expectFileExists('.gitignore')->toBeFalse(); - - file_put_contents(base_path('.gitignore'), ' - # foobar - #foobar - foobar - baz - '); - - register( - Builder::make()->removeFromGitignore('foobar') - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - expectFileContents('.gitignore') - ->not->toContain('foobar') - ->toContain('baz'); -}); - -//-------------------------------------------------------------------------- -// Publishes configs -//-------------------------------------------------------------------------- -it('publishes configs', function () { - expectFileExists('destination.json')->toBeFalse(); - - register( - Builder::make()->publishesConfigs([ - package_path('tests/Stubs/Integration/source-one.json') => 'destination.json', - ]), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - expectFileExists('destination.json')->toBeTrue(); -}); - -//-------------------------------------------------------------------------- -// Publishes workflows -//-------------------------------------------------------------------------- -it('publishes workflows', function () { - expectFileExists('.github/workflows/workflow.yml')->toBeFalse(); - - register( - Builder::make()->publishesWorkflows([ - package_path('tests/Stubs/Integration/source-one.json') => '.github/workflows/workflow.yml', - ]), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => true])->assertSuccessful(); - - expectFileExists('.github/workflows/workflow.yml')->toBeTrue(); -}); - -//-------------------------------------------------------------------------- -// Invokes hooks -//-------------------------------------------------------------------------- -it('invokes beforeInstall hooks', function () { - $callableOne = new CallableFake; - $callableTwo = new CallableFake; - - register( - Builder::make()->beforeInstall($callableOne), - Builder::make()->beforeInstall($callableTwo), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - expect($callableOne)->assertTimesInvoked(1); - expect($callableTwo)->assertTimesInvoked(1); -}); - -it('invokes afterInstall hooks', function () { - $callableOne = new CallableFake; - $callableTwo = new CallableFake; - - register( - Builder::make()->afterInstall($callableOne), - Builder::make()->afterInstall($callableTwo), - ); - - $this->artisan('workspace:install', ['--quickly' => true, '--publish-workflows' => false])->assertSuccessful(); - - expect($callableOne)->assertTimesInvoked(1); - expect($callableTwo)->assertTimesInvoked(1); -}); diff --git a/tests/Feature/IntegrateCommandTest.php b/tests/Feature/IntegrateCommandTest.php deleted file mode 100644 index f0c9c61..0000000 --- a/tests/Feature/IntegrateCommandTest.php +++ /dev/null @@ -1,137 +0,0 @@ - pugreSkeleton()); -beforeEach(fn () => Process::fake()); -afterAll(fn () => pugreSkeleton()); - -//-------------------------------------------------------------------------- -// Integrates with vscode -//-------------------------------------------------------------------------- -it('removes .vscode from gitignore', function () { - // Assert .gitignore doesn't exist - expectFileExists('.gitignore')->toBeFalse(); - // Add .vscode to gitignore - gitignore()->addToGitignore('.vscode'); - // Assert that it's there - expect(file_get_contents(base_path('.gitignore'))) - ->toContain('.vscode'); - - $this->artisan('workspace:integrate', ['--editor' => 'vscode'])->assertSuccessful(); - - // Assert string is removed from .gitignore - expectFileContents('.gitignore') - ->not->toContain('.vscode'); -}); - -it('publishes vscode recommended extensions', function () { - // Assert extentions.json doesn't exist - expectFileExists('.vscode/extentions.json')->toBeFalse(); - - register( - Builder::make()->provideVscodeRecommendedPlugins('foo'), - ); - - $this->artisan('workspace:integrate', ['--editor' => 'vscode'])->assertSuccessful(); - - // Assert string is present in extensions.json - expectFileContents('.vscode/extensions.json') - ->json() - ->recommendations - ->toContain('foo'); -}); - -it('publishes vscode unwanted extensions', function () { - // Assert extentions.json doesn't exist - expectFileExists('.vscode/extentions.json')->toBeFalse(); - - register( - Builder::make()->provideVscodeAvoidPlugins('foo'), - ); - - $this->artisan('workspace:integrate', ['--editor' => 'vscode'])->assertSuccessful(); - - // Assert string is present in extensions.json - expectFileContents('.vscode/extensions.json') - ->json() - ->unwantedRecommendations - ->toContain('foo'); -}); - -it('publishes vscode workspace config', function () { - // Assert settings.json doesn't exist - expectFileExists('.vscode/settings.json')->toBeFalse(); - - register( - Builder::make()->provideVscodeWorkspaceConfig([ - 'foobar.enabled' => true, - ]), - ); - - $this->artisan('workspace:integrate', ['--editor' => 'vscode'])->assertSuccessful(); - - // Assert string is present in settings.json - expectFileContents('.vscode/settings.json') - ->json() - ->{'foobar.enabled'} - ->toBeTrue(); -}); - -//-------------------------------------------------------------------------- -// Integrates with phpstorm -//-------------------------------------------------------------------------- -it('removes .idea from gitignore', function () { - // Assert .gitignore doesn't exist - expectFileExists('.gitignore')->toBeFalse(); - // Add .idea to gitignore - gitignore()->addToGitignore('.idea'); - // Assert that it's there - expect(file_get_contents(base_path('.gitignore'))) - ->toContain('.idea'); - - $this->artisan('workspace:integrate', ['--editor' => 'phpstorm'])->assertSuccessful(); - - // Assert string is removed from .gitignore - expectFileContents('.gitignore') - ->not->toContain('.idea'); -}); - -it('publishes phpstorm required plugins')->todo(); -it('publishes phpstorm suggested plugins')->todo(); -it('publishes phpstorm workspace config')->todo(); - -//-------------------------------------------------------------------------- -// Invokes hooks -//-------------------------------------------------------------------------- -it('invokes beforeIntegrate hooks', function () { - $callableOne = new CallableFake; - $callableTwo = new CallableFake; - - register( - Builder::make()->afterIntegration($callableOne), - Builder::make()->afterIntegration($callableTwo), - ); - - $this->artisan('workspace:integrate', ['--editor' => 'vscode', '--quickly' => true])->assertSuccessful(); - - expect($callableOne)->assertTimesInvoked(1); - expect($callableTwo)->assertTimesInvoked(1); -}); - -it('invokes afterIntegrate hooks', function () { - $callableOne = new CallableFake; - $callableTwo = new CallableFake; - - register( - Builder::make()->afterIntegration($callableOne), - Builder::make()->afterIntegration($callableTwo), - ); - - $this->artisan('workspace:integrate', ['--editor' => 'vscode', '--quickly' => true])->assertSuccessful(); - - expect($callableOne)->assertTimesInvoked(1); - expect($callableTwo)->assertTimesInvoked(1); -}); diff --git a/tests/Feature/UpdateCommandTest.php b/tests/Feature/UpdateCommandTest.php deleted file mode 100644 index 355fd7f..0000000 --- a/tests/Feature/UpdateCommandTest.php +++ /dev/null @@ -1,89 +0,0 @@ - pugreSkeleton()); -beforeEach(fn () => Process::fake()); -afterAll(fn () => pugreSkeleton()); - -//-------------------------------------------------------------------------- -// Updates dependencies -//-------------------------------------------------------------------------- - -it('updates internal workspace dependency', function () { - $this->artisan('workspace:update', ['--publish-workflows' => false])->assertSuccessful(); - - Process::assertRan('composer update gedachtegoed/workspace --no-interaction'); -}); - -it('updates composer dependencies', function () { - register( - Builder::make()->composerUpdate('foo/bar'), - Builder::make()->composerUpdate('bar/baz'), - ); - - $this->artisan('workspace:update', ['--publish-workflows' => false])->assertSuccessful(); - - $dependencies = implode(' ', resolve(Aggregator::class)->composerUpdate()); - Process::assertRan("composer update {$dependencies}"); -}); - -it('updates npm dependencies', function () { - register( - Builder::make()->npmUpdate('foo/bar'), - Builder::make()->npmUpdate('bar/baz'), - ); - - $this->artisan('workspace:update', ['--publish-workflows' => false])->assertSuccessful(); - - $dependencies = implode(' ', resolve(Aggregator::class)->npmUpdate()); - Process::assertRan("npm update {$dependencies}"); -}); - -//-------------------------------------------------------------------------- -// Calls workspace:install internally -//-------------------------------------------------------------------------- -it('calls workspace:install', function () { - Artisan::shouldReceive('callSilently') - ->with('workspace:install') - ->once(); - - $this->artisan('workspace:update', ['--publish-workflows' => false])->assertSuccessful(); -})->todo(); - -//-------------------------------------------------------------------------- -// Invokes hooks -//-------------------------------------------------------------------------- -it('invokes beforeUpdate hooks', function () { - $callableOne = new CallableFake; - $callableTwo = new CallableFake; - - register( - Builder::make()->beforeUpdate($callableOne), - Builder::make()->beforeUpdate($callableTwo), - ); - - $this->artisan('workspace:update', ['--publish-workflows' => false])->assertSuccessful(); - - expect($callableOne)->assertTimesInvoked(1); - expect($callableTwo)->assertTimesInvoked(1); -}); - -it('invokes afterUpdate hooks', function () { - $callableOne = new CallableFake; - $callableTwo = new CallableFake; - - register( - Builder::make()->afterUpdate($callableOne), - Builder::make()->afterUpdate($callableTwo), - ); - - $this->artisan('workspace:update', ['--publish-workflows' => false])->assertSuccessful(); - - expect($callableOne)->assertTimesInvoked(1); - expect($callableTwo)->assertTimesInvoked(1); -}); diff --git a/tests/Integration/IntegrationTest.php b/tests/Integration/IntegrationTest.php index c9b4f8d..7eaba83 100644 --- a/tests/Integration/IntegrationTest.php +++ b/tests/Integration/IntegrationTest.php @@ -20,8 +20,8 @@ ->classes()->not->toBeFinal(); test("integrations don't use forbidden globals") - ->expectIntegrationNamespace() - ->expect(['dd', 'dump', 'ray'])->not->toBeUsed(); + ->expect(['dd', 'dump', 'ray']) + ->not->toBeUsedIn(integrationNamespace()); //-------------------------------------------------------------------------- // Configured Integrations (also coveres inline Builders) @@ -39,10 +39,13 @@ //-------------------------------------------------------------------------- function expectIntegrationNamespace() { - return expect( - str(ServiceProvider::class) - ->beforeLast('\\') - ->append('\\Integrations') - ->toString() - ); + return expect(integrationNamespace()); +} + +function integrationNamespace() +{ + return str(ServiceProvider::class) + ->beforeLast('\\') + ->append('\\Integrations') + ->toString(); } diff --git a/tests/Pest.php b/tests/Pest.php index fda3a74..e01a09c 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,90 +1,5 @@ in('Unit', 'Integration'); - -uses(Tests\TestCase::class) - ->group('integration') - ->in('Feature'); - -/* -|-------------------------------------------------------------------------- -| Expectations -|-------------------------------------------------------------------------- -| -| When you're writing tests, you often need to check that values meet certain conditions. The -| "expect()" function gives you access to a set of "expectations" methods that you can use -| to assert different things. Of course, you may extend the Expectation API at any time. -| -*/ - -function expectFileContents($path) -{ - return expect(file_get_contents(base_path($path))); -} - -function expectFileExists($path) -{ - return expect(file_exists(base_path($path))); -} - -/* -|-------------------------------------------------------------------------- -| Functions -|-------------------------------------------------------------------------- -| -| While Pest is very powerful out-of-the-box, you may have some testing code specific to your -| project that you don't want to repeat in every file. Here you can also expose helpers as -| global functions to help you to reduce the number of lines of code in your test files. -| -*/ - -function register(...$args) -{ - config(['workspace-integrations' => [ - ...$args, - ]]); -} - -function pugreSkeleton() -{ - $purgeSkeleton = new class - { - use InteractsWithDirectories; - - public function __construct() - { - $this->replaceDirectory( - package_path('tests/workbench-skeleton'), - package_path('skeleton') - ); - } - }; - - new $purgeSkeleton; -} - -function gitignore() -{ - return new class - { - use UpdatesGitignore; - }; -} +uses(Tests\TestCase::class)->in('Integration'); diff --git a/tests/Stubs/Integration/IntegrationStub.php b/tests/Stubs/Integration/IntegrationStub.php deleted file mode 100644 index a1ed68f..0000000 --- a/tests/Stubs/Integration/IntegrationStub.php +++ /dev/null @@ -1,19 +0,0 @@ -publishesConfigs([ - 'source-one.json' => 'destination.json', - ]); - - $this->publishesWorkflows([ - 'source-one.json' => 'destination.json', - ]); - } -} diff --git a/tests/Stubs/Integration/source-one.json b/tests/Stubs/Integration/source-one.json deleted file mode 100644 index 0db3279..0000000 --- a/tests/Stubs/Integration/source-one.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - -} diff --git a/tests/Stubs/Integration/source-two.json b/tests/Stubs/Integration/source-two.json deleted file mode 100644 index 0db3279..0000000 --- a/tests/Stubs/Integration/source-two.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - -} diff --git a/tests/Unit/AggregatorTest.php b/tests/Unit/AggregatorTest.php deleted file mode 100644 index f925611..0000000 --- a/tests/Unit/AggregatorTest.php +++ /dev/null @@ -1,433 +0,0 @@ -expect(fn () => Aggregator::make([])) - ->integrations() - ->toHaveCount(1) - ->composerRequireDev() - ->toContain('tightenco/duster'); - -it('resolves aggregator with configured integrations from the container', function () { - config(['workspace-integrations' => [ - Builder::make()->composerRequireDev('package/one'), - ]]); - - expect(resolve(Aggregator::class)) - ->composerRequireDev() - ->toContain( - 'package/one', - ); -}); - -it('combines default and configured integrations', function () { - register( - Builder::make()->composerRequireDev('foo/bar:^2'), - Builder::make()->composerRequireDev('bar/baz'), - ); - - expect(resolve(Aggregator::class)) - ->integrations() - ->toHaveCount( - 2 + count(Aggregator::DEFAULT_INTEGRATIONS) - ); -}); - -it('aggregates Duster lint scripts to be installed') - ->expect(fn () => Aggregator::make([ - Builder::make()->provideDusterLintConfig([ - 'extra-linter' => ['some-command'], - ]), - Builder::make()->provideDusterLintConfig([ - 'another-extra-linter' => ['some-command'], - ]), - ])) - ->dusterLintConfig() - ->toMatchArray([ - 'extra-linter' => ['some-command'], - 'another-extra-linter' => ['some-command'], - ]); - -it('aggregates Duster fix scripts to be installed') - ->expect(fn () => Aggregator::make([ - Builder::make()->provideDusterFixConfig([ - 'extra-fixer' => ['some-command'], - ]), - Builder::make()->provideDusterFixConfig([ - 'another-extra-fixer' => ['some-command'], - ]), - ])) - ->dusterFixConfig() - ->toMatchArray([ - 'extra-fixer' => ['some-command'], - 'another-extra-fixer' => ['some-command'], - ]); - -//-------------------------------------------------------------------------- -// Package managers -//-------------------------------------------------------------------------- -it('aggregates composer install definitions', function () { - $aggregate = Aggregator::make([ - Builder::make()->composerRequireDev('package/one'), - Builder::make()->composerRequireDev([ - 'package/two', - 'package/three:^2.3', - ]), - ]); - - expect($aggregate) - ->composerRequireDev() - ->toContain( - 'package/one', - 'package/two', - 'package/three:^2.3', - ); -}); - -it('aggregates composer update definitions', function () { - $aggregate = Aggregator::make([ - Builder::make()->composerUpdate('package/one'), - Builder::make()->composerUpdate([ - 'package/two', - 'package/three', - ]), - ]); - - expect($aggregate) - ->composerUpdate() - ->toContain( - 'package/one', - 'package/two', - 'package/three', - ); -}); - -it('aggregates composer script definitions', function () { - $aggregate = Aggregator::make([ - Builder::make()->composerScripts([ - 'some-alias' => 'some-command', - ]), - Builder::make()->composerScripts([ - 'some-other-alias' => 'some-other-command', - ]), - ]); - - expect($aggregate) - ->composerScripts() - ->toEqual([ - 'some-alias' => 'some-command', - 'some-other-alias' => 'some-other-command', - ]); -}); - -it('aggregates nested composer script definitions', function () { - $aggregate = Aggregator::make([ - Builder::make()->composerScripts([ - 'some-alias' => 'some-command', - ]), - Builder::make()->composerScripts([ - 'post-update-cmd' => [ - 'some-command', - ], - ]), - Builder::make()->composerScripts([ - 'post-update-cmd' => [ - 'some-other-command', - ], - ]), - ]); - - expect($aggregate) - ->composerScripts() - ->toEqual([ - 'some-alias' => 'some-command', - 'post-update-cmd' => [ - 'some-command', - 'some-other-command', - ], - ]); -}); - -it('aggregates npm install definitions') - ->expect(fn () => Aggregator::make([ - Builder::make()->npmInstallDev('package/one'), - Builder::make()->npmInstallDev([ - 'package/two', - 'package/three:^2.3', - ]), - ])) - ->npmInstallDev() - ->toContain( - 'package/one', - 'package/two', - 'package/three:^2.3', - ); - -it('aggregates npm update definitions', function () { - $aggregate = Aggregator::make([ - Builder::make()->npmUpdate('package/one'), - Builder::make()->npmUpdate([ - 'package/two', - 'package/three:^2.3', - ]), - ]); - - expect($aggregate) - ->npmUpdate() - ->toContain( - 'package/one', - 'package/two', - 'package/three:^2.3', - ); -}); - -//-------------------------------------------------------------------------- -// Configs -//-------------------------------------------------------------------------- -it('aggregates config files to be published', function () { - $aggregate = Aggregator::make([ - Builder::make()->publishesConfigs([package_path('tests/Stubs/Integration/source-one.json') => 'destination-one']), - Builder::make()->publishesConfigs([package_path('tests/Stubs/Integration/source-two.json') => 'destination-two']), - ]); - - expect($aggregate) - ->publishesConfigs() - ->toHaveCount(3); // Count is 3 in stead of expected 2 because duster comes as a default Integration -}); - -it('maps configs files relative to the integration class path and the project base path', function () { - $aggregate = Aggregator::make([ - IntegrationStub::class, - ]); - - expect($aggregate) - ->publishesConfigs() - ->toMatchArray([ - realpath('tests/Stubs/Integration') . '/source-one.json' => base_path('destination.json'), - ]); -}); - -it('maps configs files relative to inlined integration invokation path and the project base path', function () { - $aggregate = Aggregator::make([ - Builder::make()->publishesConfigs([ - package_path('tests/Stubs/Integration/source-one.json') => 'destination.json', - ]), - ]); - - expect($aggregate) - ->publishesConfigs() - ->toMatchArray([ - package_path('tests/Stubs/Integration/source-one.json') => base_path('destination.json'), - ]); -}); - -it('aggregates workflow files to be published', function () { - $aggregate = Aggregator::make([ - Builder::make()->publishesWorkflows([package_path('tests/Stubs/Integration/source-one.json') => 'destination-one']), - Builder::make()->publishesWorkflows([package_path('tests/Stubs/Integration/source-two.json') => 'destination-two']), - ]); - - expect($aggregate) - ->publishesWorkflows() - ->toHaveCount(2); -}); - -it('maps workflow files relative to the integration class path and the project base path', function () { - $aggregate = Aggregator::make([ - IntegrationStub::class, - ]); - - expect($aggregate) - ->publishesWorkflows() - ->toMatchArray([ - package_path('tests/Stubs/Integration/source-one.json') => base_path('destination.json'), - ]); -}); - -it('maps workflow files relative to inlined integration invokation path and the project base path', function () { - $aggregate = Aggregator::make([ - Builder::make()->publishesWorkflows([ - package_path('tests/Stubs/Integration/source-one.json') => 'destination.json', - ]), - ]); - - expect($aggregate) - ->publishesWorkflows() - ->toMatchArray([ - package_path('tests/Stubs/Integration/source-one.json') => base_path('destination.json'), - ]); -}); - -//-------------------------------------------------------------------------- -// Gitignore -//-------------------------------------------------------------------------- -it('aggregates gitignore lines to be added') - ->expect(fn () => Aggregator::make([ - Builder::make()->addToGitignore('file-one'), - Builder::make()->addToGitignore([ - 'file-two', - 'file-three', - ]), - ])) - ->addToGitignore() - ->toMatchArray([ - 'file-one', - 'file-two', - 'file-three', - ]); - -it('aggregates gitignore lines to be removed') - ->expect(fn () => Aggregator::make([ - Builder::make()->removeFromGitignore('file-one'), - Builder::make()->removeFromGitignore([ - 'file-two', - 'file-three', - ]), - ])) - ->removeFromGitignore() - ->toMatchArray([ - 'file-one', - 'file-two', - 'file-three', - ]); - -//-------------------------------------------------------------------------- -// IDE integrations -//-------------------------------------------------------------------------- -it('aggregates vscode workspace config definitions') - ->expect(fn () => Aggregator::make([ - Builder::make()->provideVscodeWorkspaceConfig(['setting-one.enabled' => true]), - Builder::make()->provideVscodeWorkspaceConfig(['setting-two.enabled' => true]), - ])) - ->provideVscodeWorkspaceConfig() - ->toMatchArray([ - 'setting-one.enabled' => true, - 'setting-two.enabled' => true, - ]); - -it('aggregates vscode reccommended plugin definitions') - ->expect(fn () => Aggregator::make([ - Builder::make()->provideVscodeRecommendedPlugins('gdd.plugin-one'), - Builder::make()->provideVscodeRecommendedPlugins('gdd.plugin-two'), - ])) - ->provideVscodeRecommendedPlugins() - ->toMatchArray([ - 'gdd.plugin-one', - 'gdd.plugin-two', - ]); - -it('aggregates vscode avoid plugin definitions') - ->expect(fn () => Aggregator::make([ - Builder::make()->provideVscodeAvoidPlugins('gdd.plugin-one'), - Builder::make()->provideVscodeAvoidPlugins('gdd.plugin-two'), - ])) - ->provideVscodeAvoidPlugins() - ->toMatchArray([ - 'gdd.plugin-one', - 'gdd.plugin-two', - ]); - -it('intelligently merges vscode reccomended and avoid plugin definitions')->todo(); - -it('aggregates phpstorm workspace config definitions') - ->expect(fn () => Aggregator::make([ - Builder::make()->providePhpStormWorkspaceConfig(['setting-one.enabled' => true]), - Builder::make()->providePhpStormWorkspaceConfig(['setting-two.enabled' => true]), - ])) - ->providePhpStormWorkspaceConfig() - ->toMatchArray([ - 'setting-one.enabled' => true, - 'setting-two.enabled' => true, - ]); - -it('aggregates phpstorm required plugin definitions') - ->expect(fn () => Aggregator::make([ - Builder::make()->providePhpStormRequiredPlugins('gdd.plugin-one'), - Builder::make()->providePhpStormRequiredPlugins('gdd.plugin-two'), - ])) - ->providePhpStormRequiredPlugins() - ->toMatchArray([ - 'gdd.plugin-one', - 'gdd.plugin-two', - ]); - -it('aggregates phpstorm suggested plugin definitions') - ->expect(fn () => Aggregator::make([ - Builder::make()->providePhpStormSuggestedPlugins('gdd.plugin-one'), - Builder::make()->providePhpStormSuggestedPlugins('gdd.plugin-two'), - ])) - ->providePhpStormSuggestedPlugins() - ->toMatchArray([ - 'gdd.plugin-one', - 'gdd.plugin-two', - ]); - -it('aggregates phpstorm disabled plugin definitions')->todo('Not sure if possible'); -it('intelligently merges phpstorm reccomended and avoid plugin definitions')->todo(); - -//-------------------------------------------------------------------------- -// Lifecycle Hooks -//-------------------------------------------------------------------------- -it('aggregates beforeInstall hooks') - ->expect(fn () => Aggregator::make([ - Builder::make()->beforeInstall(fn () => null), - Builder::make()->beforeInstall(fn () => null), - ])) - ->beforeInstall() - ->toHaveCount(2); - -it('aggregates afterInstall hooks') - ->expect(fn () => Aggregator::make([ - Builder::make()->afterInstall(fn () => null), - Builder::make()->afterInstall(fn () => null), - ])) - ->afterInstall() - ->toHaveCount(2); - -it('aggregates beforeUpdate hooks') - ->expect(fn () => Aggregator::make([ - Builder::make()->beforeUpdate(fn () => null), - Builder::make()->beforeUpdate(fn () => null), - ])) - ->beforeUpdate() - ->toHaveCount(2); - -it('aggregates afterUpdate hooks') - ->expect(fn () => Aggregator::make([ - Builder::make()->afterUpdate(fn () => null), - Builder::make()->afterUpdate(fn () => null), - ])) - ->afterUpdate() - ->toHaveCount(2); - -it('aggregates beforeIntegrate hooks') - ->expect(fn () => Aggregator::make([ - Builder::make()->beforeIntegration(fn () => null), - Builder::make()->beforeIntegration(fn () => null), - ])) - ->beforeIntegration() - ->toHaveCount(2); - -it('aggregates afterIntegrate hooks') - ->expect(fn () => Aggregator::make([ - Builder::make()->afterIntegration(fn () => null), - Builder::make()->afterIntegration(fn () => null), - ])) - ->afterIntegration() - ->toHaveCount(2); diff --git a/tests/Unit/ArchitectureTest.php b/tests/Unit/ArchitectureTest.php deleted file mode 100644 index b257465..0000000 --- a/tests/Unit/ArchitectureTest.php +++ /dev/null @@ -1,18 +0,0 @@ -expect(['dd', 'dump', 'ray'])->not->toBeUsed(); - -//-------------------------------------------------------------------------- -// Portable Integration sanity checks -//-------------------------------------------------------------------------- -test("doesn't use final classes") - ->expect('Gedachtegoed\\Workspace\\Core') - ->classes()->not->toBeFinal(); - -test('concerns namespaces only contains traits') - ->expect('Core\\Concerns')->toBeTraits() - ->expect('Commands\\Concerns')->toBeTraits(); diff --git a/tests/Unit/BuilderTest.php b/tests/Unit/BuilderTest.php deleted file mode 100644 index 7900531..0000000 --- a/tests/Unit/BuilderTest.php +++ /dev/null @@ -1,21 +0,0 @@ -expect(fn () => Builder::make()->publishesConfigs([ - 'non-existing-path' => 'destination.json', - ])) - ->throws(ConfigNotFoundException::class); - -it("throws exception when workflow source file doesn't exist") - ->expect(fn () => Builder::make()->publishesWorkflows([ - 'non-existing-path' => 'destination.json', - ])) - ->throws(WorkflowNotFoundException::class); diff --git a/tests/workbench-skeleton/README.md b/tests/workbench-skeleton/README.md deleted file mode 100644 index 09a1682..0000000 --- a/tests/workbench-skeleton/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# DO NOT TOUCH THIS DIRECTORY - -Used to reset the internal testing workbench to a default state for Integration testing diff --git a/tests/workbench-skeleton/bootstrap/cache/.gitkeep b/tests/workbench-skeleton/bootstrap/cache/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/workbench-skeleton/bootstrap/storage/framework/views/.gitkeep b/tests/workbench-skeleton/bootstrap/storage/framework/views/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/workbench-skeleton/bootstrap/storage/logs/.gitkeep b/tests/workbench-skeleton/bootstrap/storage/logs/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/workbench-skeleton/composer.json b/tests/workbench-skeleton/composer.json deleted file mode 100644 index 3161d9c..0000000 --- a/tests/workbench-skeleton/composer.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "gedachtegoed/workspace", - "type": "library", - "license": "MIT", - "minimum-stability": "stable", - "prefer-stable": true, - "authors": [ - { - "name": "Willem Leuverink", - "email": "willem@leuver.ink", - "homepage": "https://leuver.ink" - } - ], - "extra": { - "thanks": [ - { - "name": "tightenco/duster", - "url": "https://github.com/tighten/duster" - }, - { - "name": "laravel/prompts", - "url": "https://github.com/laravel/prompts" - }, - { - "name": "timacdonald/callable-fake", - "url": "https://github.com/timacdonald/callable-fake" - } - ] - } -} diff --git a/tests/workbench-skeleton/storage/framework/views/.gitkeep b/tests/workbench-skeleton/storage/framework/views/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/tests/workbench-skeleton/storage/logs/.gitkeep b/tests/workbench-skeleton/storage/logs/.gitkeep deleted file mode 100644 index e69de29..0000000