diff --git a/.gitattributes b/.gitattributes index 87ba0555b..2676ce3e1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,9 +1,11 @@ # Exclude build/test files from the release .github/ export-ignore +bin/get-packages export-ignore tests/ export-ignore .gitattributes export-ignore .gitignore export-ignore .php-cs-fixer.dist.php export-ignore +monorepo-builder.php export-ignore phpstan.neon.dist export-ignore phpstan-baseline.php export-ignore phpunit.xml export-ignore diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index b4e6c6514..453455745 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -43,4 +43,32 @@ __:white_check_mark: Good Example__ > Value should be a valid email address __:x: Bad Example__ -> Value should be a valid email address! \ No newline at end of file +> Value should be a valid email address! + +# Release Workflow + +> [!NOTE] +> Tempest uses sub-splits to allow components to be installed as individual packages. The following outlines how this process works. + +## Workflow Steps + +1. **Trigger Event** + - When a pull request is merged, or a new tag is created, the `.github/workflows/subsplit-packages.yml` action is run. + +2. **Package Information Retrieval** + - When the `subsplit-packages.yml` is run, it calls `bin/get-packages`. + - This PHP script uses a combination of Composer and the filesystem to return (in JSON) some information about every package. It returns the: + - **Directory** + - **Name** + - **Package** + - **Organization** + - **Repository** + +3. **Action Matrix Creation** + - The result of the `get-packages` command is then used to create an action matrix. + - This ensures that the next steps are performed for _every_ package discovered. + +4. **Monorepo Split Action** + - The `symplify/monorepo-split-github-action@v2.3.0` GitHub action is called for every package and provided the necessary information (destination repo, directory, etc.). + - This action takes any changes and pushes them to the sub-split repository determined by combining the "Organization" and "Repository" values returned in step 2. + - Depending on whether a tag is found or not, a tag is also supplied so the repository is tagged appropriately. \ No newline at end of file diff --git a/.github/workflows/subsplit-packages.yml b/.github/workflows/subsplit-packages.yml new file mode 100644 index 000000000..1d7f6f24a --- /dev/null +++ b/.github/workflows/subsplit-packages.yml @@ -0,0 +1,75 @@ +name: 'Sub-split Packages' + +on: + push: + branches: [ main ] + tags: [ '*' ] + +env: + GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} + +jobs: + get_packages: + name: Get Packages + runs-on: ubuntu-latest + steps: + - name: Set Up PHP + uses: shivammathur/setup-php@v2 + with: + php-version: 8.3 + coverage: none + + - uses: actions/checkout@v2 + + - name: Get Packages + id: get_json + run: echo "::set-output name=json::$(bin/get-packages)" + + - name: Output Packages + run: echo "${{ steps.get_json.outputs.json }}" + outputs: + matrix: ${{ steps.get_json.outputs.json }} + + packages_split: + name: Split Package ${{ matrix.package.name }} + needs: get_packages + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + package: ${{ fromJson(needs.get_packages.outputs.matrix) }} + steps: + - uses: actions/checkout@v2 + # no tag + - + if: "!startsWith(github.ref, 'refs/tags/')" + uses: "symplify/monorepo-split-github-action@v2.3.0" + with: + # ↓ split "src/Tempest/Console" directory + package_directory: '${{ matrix.package.directory }}' + + # ↓ into https://github.com/tempestphp/tempest-console repository + repository_organization: '${{ matrix.package.organization }}' + repository_name: '${{ matrix.package.repository }}' + + # ↓ the user signed under the split commit + user_name: "aidan-casey" + user_email: "aidan@caseyhouse.net" + + # with tag + - + if: "startsWith(github.ref, 'refs/tags/')" + uses: "symplify/monorepo-split-github-action@v2.3.0" + with: + tag: ${GITHUB_REF#refs/tags/} + + # ↓ split "src/Tempest/Console" directory + package_directory: '${{ matrix.package.directory }}' + + # ↓ into https://github.com/tempestphp/tempest-console repository + repository_organization: '${{ matrix.package.organization }}' + repository_name: '${{ matrix.package.repository }}' + + # ↓ the user signed under the split commit + user_name: "aidan-casey" + user_email: "aidan@caseyhouse.net" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0d09a962f..a752a236d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,14 @@ .idea/ build/ +sessions/ vendor/ +src/Tempest/database.sqlite +tests/Fixtures/database.sqlite +tests/Unit/Console/test-console.log .env .php-cs-fixer.cache .phpunit.result.cache -tests/fixtures/database.sqlite composer.lock -*.cache.php -sessions/ debug.log tempest.log -tests/Unit/Console/test-console.log \ No newline at end of file +*.cache.php \ No newline at end of file diff --git a/bin/get-packages b/bin/get-packages new file mode 100755 index 000000000..08ee51cfe --- /dev/null +++ b/bin/get-packages @@ -0,0 +1,67 @@ +#!/usr/bin/env php + + */ +function getPackages(): array { + $packages = []; + $directoryIterator = new DirectoryIterator(realpath(PACKAGES_DIRECTORY)); + + /** + * @var DirectoryIterator $directory + */ + foreach ($directoryIterator as $directory) { + if ($directory->isDot()) { + continue; + } + + $file = $directory->getRealPath() . DIRECTORY_SEPARATOR . 'composer.json'; + + if (! file_exists($file)) { + continue; + } + + $name = getPackageNameFromComposerFile($file); + $packages[] = [ + 'directory' => $directory->getRealPath(), + 'name' => $name, + 'package' => 'tempest/' . $name, + 'organization' => 'tempestphp', + 'repository' => sprintf('tempest-%s', $name), + ]; + } + + return $packages; +} + +echo json_encode(getPackages()); \ No newline at end of file diff --git a/composer.json b/composer.json index edcbedeb8..e6aa36140 100644 --- a/composer.json +++ b/composer.json @@ -2,42 +2,49 @@ "name": "tempest/framework", "description": "The PHP framework that gets out of your way.", "require": { - "php": "^8.3", - "tempest/core": "dev-main", - "ext-pdo": "*", - "vlucas/phpdotenv": "^5.6", + "egulias/email-validator": "^4.0", "ext-dom": "*", - "ext-mbstring": "*", "ext-fileinfo": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-pdo": "*", + "ext-readline": "*", + "ext-simplexml": "*", "giggsey/libphonenumber-for-php": "^8.13", - "egulias/email-validator": "^4.0", - "psr/http-message": "^2.0", - "psr/http-factory": "^1.0", - "psr/http-client": "^1.0", "guzzlehttp/guzzle": "^7.8", "laminas/laminas-diactoros": "^3.3", + "php": "^8.3", "psr/clock": "^1.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^2.0", "ramsey/uuid": "^4.7", - "ext-simplexml": "*", - "ext-libxml": "*" + "symfony/dependency-injection": "^6.0", + "symfony/http-kernel": "^6.0", + "tempest/core": "dev-main", + "tempest/highlight": "^2.0", + "vlucas/phpdotenv": "^5.6" }, "require-dev": { - "phpunit/phpunit": "^10.2", - "larapack/dd": "^1.1", - "phpstan/phpstan": "^1.10.0", + "aidan-casey/mock-client": "dev-master", "friendsofphp/php-cs-fixer": "^3.21", + "larapack/dd": "^1.1", + "nyholm/psr7": "^1.8", + "php-http/mock-client": "^1.6", "phpat/phpat": "^0.10.14", + "phpstan/phpstan": "^1.10.0", + "phpunit/phpunit": "^10.2", "spaze/phpstan-disallowed-calls": "^3.1", - "php-http/mock-client": "^1.6", - "aidan-casey/mock-client": "dev-master" + "symplify/monorepo-builder": "^11.2" }, "autoload": { - "psr-4": { - "Tempest\\": "src/Tempest" - }, "files": [ "src/Tempest/functions.php" - ] + ], + "psr-4": { + "Tempest\\": "src/Tempest", + "Tempest\\Console\\": "src/Tempest/Console/" + } }, "autoload-dev": { "psr-4": { @@ -61,5 +68,8 @@ "allow-plugins": { "php-http/discovery": true } + }, + "replace": { + "tempest/console": "self.version" } } diff --git a/monorepo-builder.php b/monorepo-builder.php new file mode 100644 index 000000000..d608ccfeb --- /dev/null +++ b/monorepo-builder.php @@ -0,0 +1,9 @@ +packageDirectories([__DIR__ . '/src/Tempest']); +}; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index eaa4da0af..4fa8c8d2e 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,5 +1,15 @@ parameters: ignoreErrors: + - + message: "#^Tempest\\\\Console\\\\Exceptions\\\\ConsoleException should be final$#" + count: 1 + path: src/Tempest/Console/Exceptions/ConsoleException.php + + - + message: "#^Calling exec\\(\\) is forbidden\\.$#" + count: 3 + path: src/Tempest/Console/Terminal/Terminal.php + - message: "#^Tempest\\\\Database\\\\Exceptions\\\\DatabaseException should be final$#" count: 1 @@ -50,6 +60,41 @@ parameters: count: 1 path: src/Tempest/HttpClient/Driver/Psr18Driver.php + - + message: "#^Access to an undefined property Tempest\\\\View\\\\View\\:\\:\\$path\\.$#" + count: 1 + path: src/View/ViewRenderer.php + + - + message: "#^Access to an undefined property Tempest\\\\View\\\\ViewRenderer\\:\\:\\$extendsParams\\.$#" + count: 1 + path: src/View/ViewRenderer.php + + - + message: "#^Access to an undefined property Tempest\\\\View\\\\ViewRenderer\\:\\:\\$extendsPath\\.$#" + count: 1 + path: src/View/ViewRenderer.php + + - + message: "#^Access to an undefined property Tempest\\\\View\\\\ViewRenderer\\:\\:\\$path\\.$#" + count: 3 + path: src/View/ViewRenderer.php + + - + message: "#^Access to an undefined property Tempest\\\\View\\\\ViewRenderer\\:\\:\\$rawParams\\.$#" + count: 1 + path: src/View/ViewRenderer.php + + - + message: "#^Call to an undefined method Tempest\\\\View\\\\ViewRenderer\\:\\:parseSlots\\(\\)\\.$#" + count: 1 + path: src/View/ViewRenderer.php + + - + message: "#^Method Tempest\\\\View\\\\ViewRenderer\\:\\:escape\\(\\) is unused\\.$#" + count: 1 + path: src/View/ViewRenderer.php + - message: "#^Call to an undefined method ReflectionType\\:\\:getName\\(\\)\\.$#" count: 2 diff --git a/src/Tempest/Console/.gitattributes b/src/Tempest/Console/.gitattributes new file mode 100644 index 000000000..fbf3c01fa --- /dev/null +++ b/src/Tempest/Console/.gitattributes @@ -0,0 +1,5 @@ +# Exclude build/test files from the release +.github/ export-ignore +.gitattributes export-ignore +.gitignore export-ignore +README.md export-ignore diff --git a/test b/test deleted file mode 100755 index 77fe9e718..000000000 --- a/test +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env php -run(); \ No newline at end of file