From 75a81516c2990221675c253ce606161016a861f5 Mon Sep 17 00:00:00 2001 From: Yan Ivanov Date: Wed, 28 Jan 2026 22:04:47 +0500 Subject: [PATCH 1/5] feat: introduce GitHub Actions --- .github/workflows/tests.yml | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..c4f2533 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,81 @@ +name: Tests + +on: + push: + pull_request: + +jobs: + phpunit: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + php: ['8.2', '8.3', '8.4', '8.5'] + db: + - name: mysql + image: mysql:8.0 + port: 3306 + container_port: 3306 + driver: mysql + collation: utf8_unicode_ci + health_cmd: "mysqladmin ping -h 127.0.0.1 -uuser -puserpass" + - name: mariadb + image: mariadb:11 + port: 3306 + container_port: 3306 + driver: mysql + collation: utf8_unicode_ci + health_cmd: "mysqladmin ping -h 127.0.0.1 -uuser -puserpass" + - name: postgres + image: postgres:16 + port: 5432 + container_port: 5432 + driver: pgsql + collation: "" + health_cmd: "pg_isready -h 127.0.0.1 -U user -d closuretabletest" + + name: PHP ${{ matrix.php }} / ${{ matrix.db.name }} + services: + db: + image: ${{ matrix.db.image }} + ports: + - ${{ matrix.db.port }}:${{ matrix.db.container_port }} + env: + MYSQL_DATABASE: closuretabletest + MYSQL_USER: user + MYSQL_PASSWORD: userpass + MYSQL_ROOT_PASSWORD: rootpass + POSTGRES_DB: closuretabletest + POSTGRES_USER: user + POSTGRES_PASSWORD: userpass + options: >- + --health-cmd "${{ matrix.db.health_cmd }}" + --health-interval 10s + --health-timeout 5s + --health-retries 5 + + env: + DB_DRIVER: ${{ matrix.db.driver }} + DB_HOST: 127.0.0.1 + DB_PORT: ${{ matrix.db.port }} + DB_USERNAME: user + DB_PASSWORD: userpass + DB_NAME: closuretabletest + DB_COLLATION: ${{ matrix.db.collation }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: pdo_mysql, pdo_pgsql + coverage: none + + - name: Install dependencies + run: composer install --no-interaction --no-progress --prefer-dist + + - name: Run tests + run: vendor/bin/phpunit From a730d8f44da9ac1c2fd3e95b3273c64ccf844ce5 Mon Sep 17 00:00:00 2001 From: Yan Ivanov Date: Wed, 28 Jan 2026 22:10:55 +0500 Subject: [PATCH 2/5] chore: use variables --- .github/workflows/tests.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c4f2533..3176e53 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,8 +21,8 @@ jobs: health_cmd: "mysqladmin ping -h 127.0.0.1 -uuser -puserpass" - name: mariadb image: mariadb:11 - port: 3306 - container_port: 3306 + port: 3366 + container_port: 3366 driver: mysql collation: utf8_unicode_ci health_cmd: "mysqladmin ping -h 127.0.0.1 -uuser -puserpass" @@ -41,11 +41,11 @@ jobs: ports: - ${{ matrix.db.port }}:${{ matrix.db.container_port }} env: - MYSQL_DATABASE: closuretabletest + MYSQL_DATABASE: ${{ matrix.db.name }} MYSQL_USER: user MYSQL_PASSWORD: userpass MYSQL_ROOT_PASSWORD: rootpass - POSTGRES_DB: closuretabletest + POSTGRES_DB: ${{ matrix.db.name }} POSTGRES_USER: user POSTGRES_PASSWORD: userpass options: >- @@ -60,7 +60,7 @@ jobs: DB_PORT: ${{ matrix.db.port }} DB_USERNAME: user DB_PASSWORD: userpass - DB_NAME: closuretabletest + DB_NAME: ${{ matrix.db.name }} DB_COLLATION: ${{ matrix.db.collation }} steps: From 499cfb727782291ed17c6a2fef56af74fe350c51 Mon Sep 17 00:00:00 2001 From: Yan Ivanov Date: Thu, 29 Jan 2026 09:55:17 +0500 Subject: [PATCH 3/5] fix: ensure deterministic order where possible --- tests/Entity/AncestorTests.php | 20 ++++++++++---------- tests/Entity/DescendantTests.php | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/Entity/AncestorTests.php b/tests/Entity/AncestorTests.php index 7e23916..57983aa 100644 --- a/tests/Entity/AncestorTests.php +++ b/tests/Entity/AncestorTests.php @@ -19,36 +19,36 @@ public function testAncestorsScope(): void { $entity = Entity::find(12); - $ancestors = $entity->ancestors()->get(); + $ancestors = $entity->ancestors()->orderBy('id')->get(); static::assertCount(3, $ancestors); - static::assertEquals([11, 10, 9], $ancestors->modelKeys()); + static::assertEquals([9, 10, 11], $ancestors->modelKeys()); } public function testAncestorsOfScope(): void { - $ancestors = Entity::ancestorsOf(12)->get(); + $ancestors = Entity::ancestorsOf(12)->orderBy('id')->get(); static::assertCount(3, $ancestors); - static::assertEquals([11, 10, 9], $ancestors->modelKeys()); + static::assertEquals([9, 10, 11], $ancestors->modelKeys()); } public function testAncestorsWithSelfScope(): void { $entity = Entity::find(12); - $ancestors = $entity->ancestorsWithSelf()->get(); + $ancestors = $entity->ancestorsWithSelf()->orderBy('id')->get(); static::assertCount(4, $ancestors); - static::assertEquals([12, 11, 10, 9], $ancestors->modelKeys()); + static::assertEquals([9, 10, 11, 12], $ancestors->modelKeys()); } public function testAncestorsWithSelfOfScope(): void { - $ancestors = Entity::ancestorsWithSelfOf(12)->get(); + $ancestors = Entity::ancestorsWithSelfOf(12)->orderBy('id')->get(); static::assertCount(4, $ancestors); - static::assertEquals([12, 11, 10, 9], $ancestors->modelKeys()); + static::assertEquals([9, 10, 11, 12], $ancestors->modelKeys()); } public function testGetAncestorsShouldNotBeEmpty(): void @@ -67,12 +67,12 @@ public function testAncestorsWhere(): void { $entity = Entity::find(12); - $ancestors = $entity->ancestors()->where('position', '<', 2)->get(); + $ancestors = $entity->ancestors()->where('position', '<', 2)->orderBy('id')->get(); static::assertInstanceOf(EntityCollection::class, $ancestors); static::assertCount(2, $ancestors); static::assertContainsOnlyInstancesOf(Entity::class, $ancestors); - static::assertEquals([11, 10], $ancestors->modelKeys()); + static::assertEquals([10, 11], $ancestors->modelKeys()); } public function testCountAncestors(): void diff --git a/tests/Entity/DescendantTests.php b/tests/Entity/DescendantTests.php index 5b90815..e0b4885 100644 --- a/tests/Entity/DescendantTests.php +++ b/tests/Entity/DescendantTests.php @@ -19,7 +19,7 @@ public function testDescendantsScope(): void { $entity = Entity::find(9); - $descendants = $entity->descendants()->get(); + $descendants = $entity->descendants()->orderBy('id')->get(); static::assertCount(6, $descendants); static::assertEquals([10, 11, 12, 13, 14, 15], $descendants->modelKeys()); @@ -27,7 +27,7 @@ public function testDescendantsScope(): void public function testDescendantsOfScope(): void { - $descendants = Entity::descendantsOf(9)->get(); + $descendants = Entity::descendantsOf(9)->orderBy('id')->get(); static::assertCount(6, $descendants); static::assertEquals([10, 11, 12, 13, 14, 15], $descendants->modelKeys()); @@ -37,7 +37,7 @@ public function testDescendantsWithSelfScope(): void { $entity = Entity::find(9); - $descendants = $entity->descendantsWithSelf()->get(); + $descendants = $entity->descendantsWithSelf()->orderBy('id')->get(); static::assertCount(7, $descendants); static::assertEquals([9, 10, 11, 12, 13, 14, 15], $descendants->modelKeys()); @@ -45,7 +45,7 @@ public function testDescendantsWithSelfScope(): void public function testDescendantsWithSelfOfScope(): void { - $descendants = Entity::descendantsWithSelfOf(9)->get(); + $descendants = Entity::descendantsWithSelfOf(9)->orderBy('id')->get(); static::assertCount(7, $descendants); static::assertEquals([9, 10, 11, 12, 13, 14, 15], $descendants->modelKeys()); @@ -63,7 +63,7 @@ public function testGetDescendants(): void public function testGetDescendantsWhere(): void { - $descendants = Entity::find(9)->descendants()->where('position', '=', 1)->get(); + $descendants = Entity::find(9)->descendants()->where('position', '=', 1)->orderBy('id')->get(); static::assertCount(1, $descendants); static::assertEquals([13], $descendants->modelKeys()); From 1d9faea6562720e8e5d3d8676cbad0a7af40f043 Mon Sep 17 00:00:00 2001 From: Yan Ivanov Date: Thu, 29 Jan 2026 10:18:39 +0500 Subject: [PATCH 4/5] fix: change port, add specific environment variables --- .github/workflows/tests.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3176e53..f01604f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,8 +21,8 @@ jobs: health_cmd: "mysqladmin ping -h 127.0.0.1 -uuser -puserpass" - name: mariadb image: mariadb:11 - port: 3366 - container_port: 3366 + port: 3306 + container_port: 3306 driver: mysql collation: utf8_unicode_ci health_cmd: "mysqladmin ping -h 127.0.0.1 -uuser -puserpass" @@ -45,6 +45,10 @@ jobs: MYSQL_USER: user MYSQL_PASSWORD: userpass MYSQL_ROOT_PASSWORD: rootpass + MARIADB_DATABASE: ${{ matrix.db.name }} + MARIADB_USER: user + MARIADB_PASSWORD: userpass + MARIADB_ROOT_PASSWORD: rootpass POSTGRES_DB: ${{ matrix.db.name }} POSTGRES_USER: user POSTGRES_PASSWORD: userpass From db7844b70e923d59195258f1cfbc8c35a6b36165 Mon Sep 17 00:00:00 2001 From: Yan Ivanov Date: Fri, 30 Jan 2026 21:15:44 +0500 Subject: [PATCH 5/5] drop MariaDB from tests --- .github/workflows/tests.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f01604f..e317d8d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -19,13 +19,6 @@ jobs: driver: mysql collation: utf8_unicode_ci health_cmd: "mysqladmin ping -h 127.0.0.1 -uuser -puserpass" - - name: mariadb - image: mariadb:11 - port: 3306 - container_port: 3306 - driver: mysql - collation: utf8_unicode_ci - health_cmd: "mysqladmin ping -h 127.0.0.1 -uuser -puserpass" - name: postgres image: postgres:16 port: 5432 @@ -45,10 +38,6 @@ jobs: MYSQL_USER: user MYSQL_PASSWORD: userpass MYSQL_ROOT_PASSWORD: rootpass - MARIADB_DATABASE: ${{ matrix.db.name }} - MARIADB_USER: user - MARIADB_PASSWORD: userpass - MARIADB_ROOT_PASSWORD: rootpass POSTGRES_DB: ${{ matrix.db.name }} POSTGRES_USER: user POSTGRES_PASSWORD: userpass