From c784cf950bb9dd749e1337e629fdabcd006b2474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Nov 2025 16:20:48 +0100 Subject: [PATCH 1/6] Add variables suggestion --- app/controllers/api/vcs.php | 63 ++++++++ composer.lock | 140 +++++++++--------- .../Response/Model/DetectionFramework.php | 7 + .../Response/Model/DetectionRuntime.php | 7 + .../Response/Model/ProviderRepository.php | 7 + 5 files changed, 157 insertions(+), 67 deletions(-) diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index a6e72bf476..fd4d04cbd0 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -14,6 +14,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Installations; use Appwrite\Utopia\Request; use Appwrite\Utopia\Response; use Appwrite\Vcs\Comment; +use Swoole\Coroutine\WaitGroup; use Utopia\App; use Utopia\CLI\Console; use Utopia\Config\Config; @@ -963,6 +964,37 @@ App::post('/v1/vcs/github/installations/:installationId/detections') throw new Exception(Exception::FUNCTION_RUNTIME_NOT_DETECTED); } } + + $wg = new WaitGroup(); + $envNames = []; + foreach ($files as $file) { + if (!(\str_starts_with($file, '.env'))) { + continue; + } + + $wg->add(); + go(function () use ($github, $owner, $repositoryName, $providerRootDirectory, $file, $wg, &$envNames) { + try { + $contentResponse = $github->getRepositoryContent($owner, $repositoryName, \rtrim($providerRootDirectory, '/') . '/' . $file); + $envFile = $contentResponse['content'] ?? ''; + + $envLines = \explode("\n", $envFile); + foreach ($envLines as $line) { + $parts = \explode('=', $line, 2); + $envName = \trim($parts[0] ?? ''); + if (!empty($envName)) { + $envNames[] = $envName; + } + } + } finally { + $wg->done(); + } + }); + } + $wg->wait(); + + $output->setAttribute('variables', \array_unique($envNames)); + $response->dynamic($output, $type === 'framework' ? Response::MODEL_DETECTION_FRAMEWORK : Response::MODEL_DETECTION_RUNTIME); }); @@ -1137,6 +1169,37 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') $repo['runtime'] = $runtimeWithVersion ?? ''; } } + + $wg = new WaitGroup(); + $envNames = []; + foreach ($files as $file) { + if (!(\str_starts_with($file, '.env'))) { + continue; + } + + $wg->add(); + go(function () use ($github, $repo, $file, $wg, &$envNames) { + try { + $contentResponse = $github->getRepositoryContent($repo['organization'], $repo['name'], $file); + $envFile = $contentResponse['content'] ?? ''; + + $envLines = \explode("\n", $envFile); + foreach ($envLines as $line) { + $parts = \explode('=', $line, 2); + $envName = \trim($parts[0] ?? ''); + if (!empty($envName)) { + $envNames[] = $envName; + } + } + } finally { + $wg->done(); + } + }); + } + $wg->wait(); + + $repo['variables'] = \array_unique($envNames); + return $repo; }; }, $repos)); diff --git a/composer.lock b/composer.lock index 87eaf28a3e..d0ea4e720a 100644 --- a/composer.lock +++ b/composer.lock @@ -2673,16 +2673,16 @@ }, { "name": "symfony/http-client", - "version": "v7.3.4", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62" + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/4b62871a01c49457cf2a8e560af7ee8a94b87a62", - "reference": "4b62871a01c49457cf2a8e560af7ee8a94b87a62", + "url": "https://api.github.com/repos/symfony/http-client/zipball/3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", + "reference": "3c0a55a2c8e21e30a37022801c11c7ab5a6cb2de", "shasum": "" }, "require": { @@ -2749,7 +2749,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.4" + "source": "https://github.com/symfony/http-client/tree/v7.3.6" }, "funding": [ { @@ -2769,7 +2769,7 @@ "type": "tidelift" } ], - "time": "2025-09-11T10:12:26+00:00" + "time": "2025-11-05T17:41:46+00:00" }, { "name": "symfony/http-client-contracts", @@ -3176,16 +3176,16 @@ }, { "name": "symfony/service-contracts", - "version": "v3.6.0", + "version": "v3.6.1", "source": { "type": "git", "url": "https://github.com/symfony/service-contracts.git", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", - "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", + "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", "shasum": "" }, "require": { @@ -3239,7 +3239,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" }, "funding": [ { @@ -3250,12 +3250,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-25T09:37:31+00:00" + "time": "2025-07-15T11:30:57+00:00" }, { "name": "tbachert/spi", @@ -3840,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "3.1.5", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "76568b81f25d89fc1e0c53f0370f139130eeb939" + "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/76568b81f25d89fc1e0c53f0370f139130eeb939", - "reference": "76568b81f25d89fc1e0c53f0370f139130eeb939", + "url": "https://api.github.com/repos/utopia-php/database/zipball/f2d01b6b38057891184f62107bf70a55bc2ea068", + "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068", "shasum": "" }, "require": { @@ -3892,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.1.5" + "source": "https://github.com/utopia-php/database/tree/3.2.0" }, - "time": "2025-11-05T10:17:55+00:00" + "time": "2025-11-06T05:41:54+00:00" }, { "name": "utopia-php/detector", @@ -3943,22 +3947,24 @@ }, { "name": "utopia-php/dns", - "version": "1.1.0", + "version": "1.1.3", "source": { "type": "git", "url": "https://github.com/utopia-php/dns.git", - "reference": "d6eca184883262bdcb4261e57491c91b16079b9a" + "reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/dns/zipball/d6eca184883262bdcb4261e57491c91b16079b9a", - "reference": "d6eca184883262bdcb4261e57491c91b16079b9a", + "url": "https://api.github.com/repos/utopia-php/dns/zipball/1e6b4bac735329c9e5ec69a6a5d899ec2d050707", + "reference": "1e6b4bac735329c9e5ec69a6a5d899ec2d050707", "shasum": "" }, "require": { "php": ">=8.3", "utopia-php/console": "0.0.*", - "utopia-php/telemetry": "0.1.*" + "utopia-php/domains": "0.9.*", + "utopia-php/telemetry": "0.1.*", + "utopia-php/validators": "^0.0.2" }, "require-dev": { "laravel/pint": "1.25.*", @@ -3992,9 +3998,9 @@ ], "support": { "issues": "https://github.com/utopia-php/dns/issues", - "source": "https://github.com/utopia-php/dns/tree/1.1.0" + "source": "https://github.com/utopia-php/dns/tree/1.1.3" }, - "time": "2025-11-03T22:49:02+00:00" + "time": "2025-11-06T19:08:29+00:00" }, { "name": "utopia-php/domains", @@ -5377,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.1", + "version": "1.5.3", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "cd712674e34136f706e9170641ed6f4ce160e772" + "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/cd712674e34136f706e9170641ed6f4ce160e772", - "reference": "cd712674e34136f706e9170641ed6f4ce160e772", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", + "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", "shasum": "" }, "require": { @@ -5422,9 +5428,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/1.5.1" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.3" }, - "time": "2025-11-04T09:55:47+00:00" + "time": "2025-11-10T09:50:41+00:00" }, { "name": "doctrine/annotations", @@ -6077,24 +6083,24 @@ }, { "name": "phpbench/container", - "version": "2.2.2", + "version": "2.2.3", "source": { "type": "git", "url": "https://github.com/phpbench/container.git", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33" + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/container/zipball/a59b929e00b87b532ca6d0edd8eca0967655af33", - "reference": "a59b929e00b87b532ca6d0edd8eca0967655af33", + "url": "https://api.github.com/repos/phpbench/container/zipball/0c7b2d36c1ea53fe27302fb8873ded7172047196", + "reference": "0c7b2d36c1ea53fe27302fb8873ded7172047196", "shasum": "" }, "require": { "psr/container": "^1.0|^2.0", - "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0" + "symfony/options-resolver": "^4.2 || ^5.0 || ^6.0 || ^7.0 || ^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^2.16", + "php-cs-fixer/shim": "^3.89", "phpstan/phpstan": "^0.12.52", "phpunit/phpunit": "^8" }, @@ -6122,22 +6128,22 @@ "description": "Simple, configurable, service container.", "support": { "issues": "https://github.com/phpbench/container/issues", - "source": "https://github.com/phpbench/container/tree/2.2.2" + "source": "https://github.com/phpbench/container/tree/2.2.3" }, - "time": "2023-10-30T13:38:26+00:00" + "time": "2025-11-06T09:05:13+00:00" }, { "name": "phpbench/phpbench", - "version": "1.4.2", + "version": "1.4.3", "source": { "type": "git", "url": "https://github.com/phpbench/phpbench.git", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018" + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpbench/phpbench/zipball/bb61ae6c54b3d58642be154eb09f4e73c3511018", - "reference": "bb61ae6c54b3d58642be154eb09f4e73c3511018", + "url": "https://api.github.com/repos/phpbench/phpbench/zipball/b641dde59d969ea42eed70a39f9b51950bc96878", + "reference": "b641dde59d969ea42eed70a39f9b51950bc96878", "shasum": "" }, "require": { @@ -6152,26 +6158,26 @@ "phpbench/container": "^2.2", "psr/log": "^1.1 || ^2.0 || ^3.0", "seld/jsonlint": "^1.1", - "symfony/console": "^6.1 || ^7.0", - "symfony/filesystem": "^6.1 || ^7.0", - "symfony/finder": "^6.1 || ^7.0", - "symfony/options-resolver": "^6.1 || ^7.0", - "symfony/process": "^6.1 || ^7.0", + "symfony/console": "^6.1 || ^7.0 || ^8.0", + "symfony/filesystem": "^6.1 || ^7.0 || ^8.0", + "symfony/finder": "^6.1 || ^7.0 || ^8.0", + "symfony/options-resolver": "^6.1 || ^7.0 || ^8.0", + "symfony/process": "^6.1 || ^7.0 || ^8.0", "webmozart/glob": "^4.6" }, "require-dev": { "dantleech/invoke": "^2.0", "ergebnis/composer-normalize": "^2.39", - "friendsofphp/php-cs-fixer": "^3.0", "jangregor/phpstan-prophecy": "^1.0", + "php-cs-fixer/shim": "^3.9", "phpspec/prophecy": "^1.22", "phpstan/extension-installer": "^1.1", "phpstan/phpstan": "^1.0", "phpstan/phpstan-phpunit": "^1.0", "phpunit/phpunit": "^10.4 || ^11.0", "rector/rector": "^1.2", - "symfony/error-handler": "^6.1 || ^7.0", - "symfony/var-dumper": "^6.1 || ^7.0" + "symfony/error-handler": "^6.1 || ^7.0 || ^8.0", + "symfony/var-dumper": "^6.1 || ^7.0 || ^8.0" }, "suggest": { "ext-xdebug": "For Xdebug profiling extension." @@ -6214,7 +6220,7 @@ ], "support": { "issues": "https://github.com/phpbench/phpbench/issues", - "source": "https://github.com/phpbench/phpbench/tree/1.4.2" + "source": "https://github.com/phpbench/phpbench/tree/1.4.3" }, "funding": [ { @@ -6222,7 +6228,7 @@ "type": "github" } ], - "time": "2025-10-26T14:21:59+00:00" + "time": "2025-11-06T19:07:31+00:00" }, { "name": "phpstan/phpstan", @@ -7871,16 +7877,16 @@ }, { "name": "symfony/console", - "version": "v7.3.5", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7" + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/cdb80fa5869653c83cfe1a9084a673b6daf57ea7", - "reference": "cdb80fa5869653c83cfe1a9084a673b6daf57ea7", + "url": "https://api.github.com/repos/symfony/console/zipball/c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", + "reference": "c28ad91448f86c5f6d9d2c70f0cf68bf135f252a", "shasum": "" }, "require": { @@ -7945,7 +7951,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.5" + "source": "https://github.com/symfony/console/tree/v7.3.6" }, "funding": [ { @@ -7965,20 +7971,20 @@ "type": "tidelift" } ], - "time": "2025-10-14T15:46:26+00:00" + "time": "2025-11-04T01:21:42+00:00" }, { "name": "symfony/filesystem", - "version": "v7.3.2", + "version": "v7.3.6", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", - "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/e9bcfd7837928ab656276fe00464092cc9e1826a", + "reference": "e9bcfd7837928ab656276fe00464092cc9e1826a", "shasum": "" }, "require": { @@ -8015,7 +8021,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.2" + "source": "https://github.com/symfony/filesystem/tree/v7.3.6" }, "funding": [ { @@ -8035,7 +8041,7 @@ "type": "tidelift" } ], - "time": "2025-07-07T08:17:47+00:00" + "time": "2025-11-05T09:52:27+00:00" }, { "name": "symfony/finder", @@ -8891,7 +8897,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8915,5 +8921,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/src/Appwrite/Utopia/Response/Model/DetectionFramework.php b/src/Appwrite/Utopia/Response/Model/DetectionFramework.php index 9aeb885f76..899ad8766e 100644 --- a/src/Appwrite/Utopia/Response/Model/DetectionFramework.php +++ b/src/Appwrite/Utopia/Response/Model/DetectionFramework.php @@ -33,6 +33,13 @@ class DetectionFramework extends Model 'description' => 'Site Output Directory', 'default' => '', 'example' => 'dist', + ]) + ->addRule('variables', [ + 'type' => self::TYPE_STRING, + 'description' => 'Environment variables found in .env files', + 'default' => [], + 'array' => true, + 'example' => ['PORT', 'NODE_ENV'], ]); } diff --git a/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php b/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php index 1c7c0be16b..20fde90491 100644 --- a/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php +++ b/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php @@ -27,6 +27,13 @@ class DetectionRuntime extends Model 'description' => 'Function install and build commands', 'default' => '', 'example' => 'npm install && npm run build', + ]) + ->addRule('variables', [ + 'type' => self::TYPE_STRING, + 'description' => 'Environment variables found in .env files', + 'default' => [], + 'array' => true, + 'example' => ['PORT', 'NODE_ENV'], ]); } diff --git a/src/Appwrite/Utopia/Response/Model/ProviderRepository.php b/src/Appwrite/Utopia/Response/Model/ProviderRepository.php index eee058a05b..ddad0b059c 100644 --- a/src/Appwrite/Utopia/Response/Model/ProviderRepository.php +++ b/src/Appwrite/Utopia/Response/Model/ProviderRepository.php @@ -53,6 +53,13 @@ class ProviderRepository extends Model 'default' => APP_DATABASE_ATTRIBUTE_DATETIME, 'example' => APP_DATABASE_ATTRIBUTE_DATETIME, 'array' => false, + ]) + ->addRule('variables', [ + 'type' => self::TYPE_STRING, + 'description' => 'Environment variables found in .env files', + 'default' => [], + 'array' => true, + 'example' => ['PORT', 'NODE_ENV'], ]); } From 831a261c04e76f5a75089ec506dc89c70a1a16ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Mon, 10 Nov 2025 16:29:34 +0100 Subject: [PATCH 2/6] Sync unit tests with DNS lib validator --- tests/unit/Network/Validators/DNSTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/unit/Network/Validators/DNSTest.php b/tests/unit/Network/Validators/DNSTest.php index 9f8928b87f..4611e00f4d 100644 --- a/tests/unit/Network/Validators/DNSTest.php +++ b/tests/unit/Network/Validators/DNSTest.php @@ -51,8 +51,10 @@ class DNSTest extends TestCase #[Retry(count: 5)] public function testCAA(): void { - $certainly = new DNS('certainly.com', Record::TYPE_CAA, 'ns1.digitalocean.com'); - $letsencrypt = new DNS('letsencrypt.org', Record::TYPE_CAA, 'ns1.digitalocean.com'); + $digitalOceanIp = '172.64.52.210'; // ping ns1.digitalocean.com + + $certainly = new DNS('certainly.com', Record::TYPE_CAA, $digitalOceanIp); + $letsencrypt = new DNS('letsencrypt.org', Record::TYPE_CAA, $digitalOceanIp); // No CAA record succeeds on main domain & subdomains for any issuer $this->assertEquals($certainly->isValid('caa.appwrite.org'), true); From 38ef0ad399df704721af79a36faf419730b74758 Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Fri, 14 Nov 2025 12:39:37 +0530 Subject: [PATCH 3/6] fix: release sdks doc --- docs/tutorials/release-sdks.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/docs/tutorials/release-sdks.md b/docs/tutorials/release-sdks.md index 0e03beca71..99c0fa4fd3 100644 --- a/docs/tutorials/release-sdks.md +++ b/docs/tutorials/release-sdks.md @@ -26,27 +26,34 @@ Before releasing SDKs, you need to: To enable SDK releases via GitHub, you need to mount SSH keys and configure GitHub authentication in your Docker environment. -#### Update docker-compose.override.yml +#### Update Dockerfile -Update `docker-compose.override.yml` to mount SSH keys and set environment variables for the `appwrite` service: +Add the following configuration to your `Dockerfile`: + +```dockerfile +ARG GH_TOKEN +ENV GH_TOKEN=your_github_token_here +RUN git config --global user.email "your-email@example.com" +RUN apk add --update --no-cache openssh-client github-cli +``` + +Replace: +- `your_github_token_here` with your GitHub personal access token (with appropriate permissions) +- `your-email@example.com` with your Git email address + +#### Update docker-compose.yml + +Add the SSH key volume mount to the `appwrite` service in `docker-compose.yml`: ```yaml services: appwrite: volumes: - ~/.ssh:/root/.ssh - environment: - - GH_TOKEN=your_github_token_here - - GIT_EMAIL=your-email@example.com + # ... other volumes ``` -Uncomment the volumes section. - -Replace: -- `your_github_token_here` with your GitHub personal access token (with appropriate permissions) -- `your-email@example.com` with your Git email address - -This mounts your SSH keys from the host machine and sets the GitHub token and email as environment variables, allowing the container to authenticate with GitHub. The git configuration is handled automatically at runtime. +This mounts your SSH keys from the host machine, allowing the container to authenticate with GitHub. ### Updating Specs From cc7b5b7dcff7143ed165447a622484ac806396fa Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Fri, 14 Nov 2025 15:05:32 +0530 Subject: [PATCH 4/6] fix: missing nullable in datetime --- .../Http/Databases/Collections/Attributes/Datetime/Create.php | 3 ++- .../Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php index 1f2098e7af..d0f45dc664 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/Databases/Collections/Attributes/Datetime/Create.php @@ -17,6 +17,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; class Create extends Action { @@ -63,7 +64,7 @@ class Create extends Action ->param('collectionId', '', new UID(), 'Collection ID. You can create a new collection using the Database service [server integration](https://appwrite.io/docs/server/databases#createCollection).') ->param('key', '', new Key(), 'Attribute Key.') ->param('required', null, new Boolean(), 'Is attribute required?') - ->param('default', null, fn (Database $dbForProject) => new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime()), 'Default value for the attribute in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.', true, ['dbForProject']) + ->param('default', null, fn (Database $dbForProject) => new Nullable(new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime())), 'Default value for the attribute in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when attribute is required.', true, ['dbForProject']) ->param('array', false, new Boolean(), 'Is attribute an array?', true) ->inject('response') ->inject('dbForProject') diff --git a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php index db5a3059f1..69d6bd2b4b 100644 --- a/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php +++ b/src/Appwrite/Platform/Modules/Databases/Http/TablesDB/Tables/Columns/Datetime/Create.php @@ -13,6 +13,7 @@ use Utopia\Database\Validator\Key; use Utopia\Database\Validator\UID; use Utopia\Swoole\Response as SwooleResponse; use Utopia\Validator\Boolean; +use Utopia\Validator\Nullable; class Create extends DatetimeCreate { @@ -55,7 +56,7 @@ class Create extends DatetimeCreate ->param('tableId', '', new UID(), 'Table ID.') ->param('key', '', new Key(), 'Column Key.') ->param('required', null, new Boolean(), 'Is column required?') - ->param('default', null, fn (Database $dbForProject) => new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime()), 'Default value for the column in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.', true, ['dbForProject']) + ->param('default', null, fn (Database $dbForProject) => new Nullable(new DatetimeValidator($dbForProject->getAdapter()->getMinDateTime(), $dbForProject->getAdapter()->getMaxDateTime())), 'Default value for the column in [ISO 8601](https://www.iso.org/iso-8601-date-and-time-format.html) format. Cannot be set when column is required.', true, ['dbForProject']) ->param('array', false, new Boolean(), 'Is column an array?', true) ->inject('response') ->inject('dbForProject') From db1b87ecbb79a9e17d545fd3a017773cf681de36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 14 Nov 2025 15:49:19 +0100 Subject: [PATCH 5/6] Add env var value detection --- app/controllers/api/vcs.php | 32 +++++++++---- src/Appwrite/Utopia/Response.php | 3 ++ .../Utopia/Response/Model/Detection.php | 22 +++++++++ .../Response/Model/DetectionFramework.php | 12 ++--- .../Response/Model/DetectionRuntime.php | 12 ++--- .../Response/Model/DetectionVariable.php | 46 +++++++++++++++++++ 6 files changed, 101 insertions(+), 26 deletions(-) create mode 100644 src/Appwrite/Utopia/Response/Model/Detection.php create mode 100644 src/Appwrite/Utopia/Response/Model/DetectionVariable.php diff --git a/app/controllers/api/vcs.php b/app/controllers/api/vcs.php index fd4d04cbd0..2ac6cd0b26 100644 --- a/app/controllers/api/vcs.php +++ b/app/controllers/api/vcs.php @@ -966,14 +966,14 @@ App::post('/v1/vcs/github/installations/:installationId/detections') } $wg = new WaitGroup(); - $envNames = []; + $envs = []; foreach ($files as $file) { if (!(\str_starts_with($file, '.env'))) { continue; } $wg->add(); - go(function () use ($github, $owner, $repositoryName, $providerRootDirectory, $file, $wg, &$envNames) { + go(function () use ($github, $owner, $repositoryName, $providerRootDirectory, $file, $wg, &$envs) { try { $contentResponse = $github->getRepositoryContent($owner, $repositoryName, \rtrim($providerRootDirectory, '/') . '/' . $file); $envFile = $contentResponse['content'] ?? ''; @@ -982,8 +982,9 @@ App::post('/v1/vcs/github/installations/:installationId/detections') foreach ($envLines as $line) { $parts = \explode('=', $line, 2); $envName = \trim($parts[0] ?? ''); + $envValue = \trim($parts[1] ?? ''); if (!empty($envName)) { - $envNames[] = $envName; + $envs[$envName] = $envValue; } } } finally { @@ -993,7 +994,15 @@ App::post('/v1/vcs/github/installations/:installationId/detections') } $wg->wait(); - $output->setAttribute('variables', \array_unique($envNames)); + $variables = []; + foreach ($envs as $key => $value) { + $variables[] = [ + 'name' => $key, + 'value' => $value, + ]; + } + + $output->setAttribute('variables', $variables); $response->dynamic($output, $type === 'framework' ? Response::MODEL_DETECTION_FRAMEWORK : Response::MODEL_DETECTION_RUNTIME); }); @@ -1171,14 +1180,14 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') } $wg = new WaitGroup(); - $envNames = []; + $envs = []; foreach ($files as $file) { if (!(\str_starts_with($file, '.env'))) { continue; } $wg->add(); - go(function () use ($github, $repo, $file, $wg, &$envNames) { + go(function () use ($github, $repo, $file, $wg, &$envs) { try { $contentResponse = $github->getRepositoryContent($repo['organization'], $repo['name'], $file); $envFile = $contentResponse['content'] ?? ''; @@ -1187,8 +1196,9 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') foreach ($envLines as $line) { $parts = \explode('=', $line, 2); $envName = \trim($parts[0] ?? ''); + $envValue = \trim($parts[1] ?? ''); if (!empty($envName)) { - $envNames[] = $envName; + $envs[$envName] = $envValue; } } } finally { @@ -1198,7 +1208,13 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories') } $wg->wait(); - $repo['variables'] = \array_unique($envNames); + $repo['variables'] = []; + foreach ($envs as $key => $value) { + $repo['variables'][] = [ + 'name' => $key, + 'value' => $value, + ]; + } return $repo; }; diff --git a/src/Appwrite/Utopia/Response.php b/src/Appwrite/Utopia/Response.php index b391f0ea72..19a451e2c0 100644 --- a/src/Appwrite/Utopia/Response.php +++ b/src/Appwrite/Utopia/Response.php @@ -59,6 +59,7 @@ use Appwrite\Utopia\Response\Model\Database; use Appwrite\Utopia\Response\Model\Deployment; use Appwrite\Utopia\Response\Model\DetectionFramework; use Appwrite\Utopia\Response\Model\DetectionRuntime; +use Appwrite\Utopia\Response\Model\DetectionVariable; use Appwrite\Utopia\Response\Model\DevKey; use Appwrite\Utopia\Response\Model\Document as ModelDocument; use Appwrite\Utopia\Response\Model\Error; @@ -316,6 +317,7 @@ class Response extends SwooleResponse public const MODEL_BRANCH = 'branch'; public const MODEL_BRANCH_LIST = 'branchList'; public const MODEL_DETECTION_FRAMEWORK = 'detectionFramework'; + public const MODEL_DETECTION_VARIABLE = 'detectionVariable'; public const MODEL_DETECTION_RUNTIME = 'detectionRuntime'; public const MODEL_VCS_CONTENT = 'vcsContent'; public const MODEL_VCS_CONTENT_LIST = 'vcsContentList'; @@ -563,6 +565,7 @@ class Response extends SwooleResponse ->setModel(new ProviderRepositoryRuntime()) ->setModel(new DetectionFramework()) ->setModel(new DetectionRuntime()) + ->setModel(new DetectionVariable()) ->setModel(new VcsContent()) ->setModel(new Branch()) ->setModel(new Runtime()) diff --git a/src/Appwrite/Utopia/Response/Model/Detection.php b/src/Appwrite/Utopia/Response/Model/Detection.php new file mode 100644 index 0000000000..007182d1e9 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/Detection.php @@ -0,0 +1,22 @@ +addRule('variables', [ + 'type' => Response::MODEL_DETECTION_VARIABLE, + 'description' => 'Environment variables found in .env files', + 'required' => false, + 'default' => [], + 'example' => new \stdClass(), + 'array' => true, + ]); + } +} diff --git a/src/Appwrite/Utopia/Response/Model/DetectionFramework.php b/src/Appwrite/Utopia/Response/Model/DetectionFramework.php index 899ad8766e..4cdf37bbcf 100644 --- a/src/Appwrite/Utopia/Response/Model/DetectionFramework.php +++ b/src/Appwrite/Utopia/Response/Model/DetectionFramework.php @@ -3,12 +3,13 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Model; -class DetectionFramework extends Model +class DetectionFramework extends Detection { public function __construct() { + parent::__construct(); + $this ->addRule('framework', [ 'type' => self::TYPE_STRING, @@ -33,13 +34,6 @@ class DetectionFramework extends Model 'description' => 'Site Output Directory', 'default' => '', 'example' => 'dist', - ]) - ->addRule('variables', [ - 'type' => self::TYPE_STRING, - 'description' => 'Environment variables found in .env files', - 'default' => [], - 'array' => true, - 'example' => ['PORT', 'NODE_ENV'], ]); } diff --git a/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php b/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php index 20fde90491..1e63929092 100644 --- a/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php +++ b/src/Appwrite/Utopia/Response/Model/DetectionRuntime.php @@ -3,12 +3,13 @@ namespace Appwrite\Utopia\Response\Model; use Appwrite\Utopia\Response; -use Appwrite\Utopia\Response\Model; -class DetectionRuntime extends Model +class DetectionRuntime extends Detection { public function __construct() { + parent::__construct(); + $this ->addRule('runtime', [ 'type' => self::TYPE_STRING, @@ -27,13 +28,6 @@ class DetectionRuntime extends Model 'description' => 'Function install and build commands', 'default' => '', 'example' => 'npm install && npm run build', - ]) - ->addRule('variables', [ - 'type' => self::TYPE_STRING, - 'description' => 'Environment variables found in .env files', - 'default' => [], - 'array' => true, - 'example' => ['PORT', 'NODE_ENV'], ]); } diff --git a/src/Appwrite/Utopia/Response/Model/DetectionVariable.php b/src/Appwrite/Utopia/Response/Model/DetectionVariable.php new file mode 100644 index 0000000000..a5a2d2acc0 --- /dev/null +++ b/src/Appwrite/Utopia/Response/Model/DetectionVariable.php @@ -0,0 +1,46 @@ +addRule('name', [ + 'type' => self::TYPE_STRING, + 'description' => 'Name of environment variable', + 'default' => '', + 'example' => 'NODE_ENV', + ]) + ->addRule('value', [ + 'type' => self::TYPE_STRING, + 'description' => 'Value of environment variable', + 'default' => '', + 'example' => 'production', + ]); + } + + /** + * Get Name + * + * @return string + */ + public function getName(): string + { + return 'DetectionVariable'; + } + + /** + * Get Type + * + * @return string + */ + public function getType(): string + { + return Response::MODEL_DETECTION_VARIABLE; + } +} From 793057c82394aaff6ce27d0222ddf62d440e257c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Ba=C4=8Do?= Date: Fri, 14 Nov 2025 18:06:20 +0100 Subject: [PATCH 6/6] Update composer.lock --- composer.lock | 86 +++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/composer.lock b/composer.lock index d0ea4e720a..bc61d61460 100644 --- a/composer.lock +++ b/composer.lock @@ -161,16 +161,16 @@ }, { "name": "appwrite/php-runtimes", - "version": "0.19.1", + "version": "0.19.2", "source": { "type": "git", "url": "https://github.com/appwrite/runtimes.git", - "reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae" + "reference": "e5c142519df5aced37de9c302971c29c079ce3d9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/runtimes/zipball/7bd0cc3cb97de625d7b07230bd91b121f88e72ae", - "reference": "7bd0cc3cb97de625d7b07230bd91b121f88e72ae", + "url": "https://api.github.com/repos/appwrite/runtimes/zipball/e5c142519df5aced37de9c302971c29c079ce3d9", + "reference": "e5c142519df5aced37de9c302971c29c079ce3d9", "shasum": "" }, "require": { @@ -210,9 +210,9 @@ ], "support": { "issues": "https://github.com/appwrite/runtimes/issues", - "source": "https://github.com/appwrite/runtimes/tree/0.19.1" + "source": "https://github.com/appwrite/runtimes/tree/0.19.2" }, - "time": "2025-05-27T07:12:56+00:00" + "time": "2025-11-11T13:44:44+00:00" }, { "name": "beberlei/assert", @@ -756,16 +756,16 @@ }, { "name": "google/protobuf", - "version": "v4.33.0", + "version": "v4.33.1", "source": { "type": "git", "url": "https://github.com/protocolbuffers/protobuf-php.git", - "reference": "b50269e23204e5ae859a326ec3d90f09efe3047d" + "reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/b50269e23204e5ae859a326ec3d90f09efe3047d", - "reference": "b50269e23204e5ae859a326ec3d90f09efe3047d", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/0cd73ccf0cd26c3e72299cce1ea6144091a57e12", + "reference": "0cd73ccf0cd26c3e72299cce1ea6144091a57e12", "shasum": "" }, "require": { @@ -794,9 +794,9 @@ "proto" ], "support": { - "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.0" + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.33.1" }, - "time": "2025-10-15T20:10:28+00:00" + "time": "2025-11-12T21:58:05+00:00" }, { "name": "league/csv", @@ -961,16 +961,16 @@ }, { "name": "mongodb/mongodb", - "version": "2.1.1", + "version": "2.1.2", "source": { "type": "git", "url": "https://github.com/mongodb/mongo-php-library.git", - "reference": "f399d24905dd42f97dfe0af9706129743ef247ac" + "reference": "0a2472ba9cbb932f7e43a8770aedb2fc30612a67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/f399d24905dd42f97dfe0af9706129743ef247ac", - "reference": "f399d24905dd42f97dfe0af9706129743ef247ac", + "url": "https://api.github.com/repos/mongodb/mongo-php-library/zipball/0a2472ba9cbb932f7e43a8770aedb2fc30612a67", + "reference": "0a2472ba9cbb932f7e43a8770aedb2fc30612a67", "shasum": "" }, "require": { @@ -986,7 +986,7 @@ "require-dev": { "doctrine/coding-standard": "^12.0", "phpunit/phpunit": "^10.5.35", - "rector/rector": "^1.2", + "rector/rector": "^2.1.4", "squizlabs/php_codesniffer": "^3.7", "vimeo/psalm": "6.5.*" }, @@ -1032,9 +1032,9 @@ ], "support": { "issues": "https://github.com/mongodb/mongo-php-library/issues", - "source": "https://github.com/mongodb/mongo-php-library/tree/2.1.1" + "source": "https://github.com/mongodb/mongo-php-library/tree/2.1.2" }, - "time": "2025-08-13T20:50:05+00:00" + "time": "2025-10-06T12:12:40+00:00" }, { "name": "mustangostang/spyc", @@ -3844,16 +3844,16 @@ }, { "name": "utopia-php/database", - "version": "3.2.0", + "version": "3.4.0", "source": { "type": "git", "url": "https://github.com/utopia-php/database.git", - "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068" + "reference": "e10b4faa4f3a3ef30a5f6d76acdb605469924aec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/database/zipball/f2d01b6b38057891184f62107bf70a55bc2ea068", - "reference": "f2d01b6b38057891184f62107bf70a55bc2ea068", + "url": "https://api.github.com/repos/utopia-php/database/zipball/e10b4faa4f3a3ef30a5f6d76acdb605469924aec", + "reference": "e10b4faa4f3a3ef30a5f6d76acdb605469924aec", "shasum": "" }, "require": { @@ -3896,9 +3896,9 @@ ], "support": { "issues": "https://github.com/utopia-php/database/issues", - "source": "https://github.com/utopia-php/database/tree/3.2.0" + "source": "https://github.com/utopia-php/database/tree/3.4.0" }, - "time": "2025-11-06T05:41:54+00:00" + "time": "2025-11-13T06:34:20+00:00" }, { "name": "utopia-php/detector", @@ -4212,16 +4212,16 @@ }, { "name": "utopia-php/framework", - "version": "0.33.28", + "version": "0.33.29", "source": { "type": "git", "url": "https://github.com/utopia-php/http.git", - "reference": "5aaa94d406577b0059ad28c78022606890dc6de0" + "reference": "6e63939fdb33b847f92839499cd6e8df626c278d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/http/zipball/5aaa94d406577b0059ad28c78022606890dc6de0", - "reference": "5aaa94d406577b0059ad28c78022606890dc6de0", + "url": "https://api.github.com/repos/utopia-php/http/zipball/6e63939fdb33b847f92839499cd6e8df626c278d", + "reference": "6e63939fdb33b847f92839499cd6e8df626c278d", "shasum": "" }, "require": { @@ -4253,9 +4253,9 @@ ], "support": { "issues": "https://github.com/utopia-php/http/issues", - "source": "https://github.com/utopia-php/http/tree/0.33.28" + "source": "https://github.com/utopia-php/http/tree/0.33.29" }, - "time": "2025-09-25T10:44:24+00:00" + "time": "2025-11-14T06:33:29+00:00" }, { "name": "utopia-php/image", @@ -5383,16 +5383,16 @@ "packages-dev": [ { "name": "appwrite/sdk-generator", - "version": "1.5.3", + "version": "1.5.5", "source": { "type": "git", "url": "https://github.com/appwrite/sdk-generator.git", - "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d" + "reference": "1f3686e41a2d10829220b74f54c80a770e9f968a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", - "reference": "1a7a3b89147aa8c1bde5247f8eeb7e4832c6016d", + "url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/1f3686e41a2d10829220b74f54c80a770e9f968a", + "reference": "1f3686e41a2d10829220b74f54c80a770e9f968a", "shasum": "" }, "require": { @@ -5428,9 +5428,9 @@ "description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms", "support": { "issues": "https://github.com/appwrite/sdk-generator/issues", - "source": "https://github.com/appwrite/sdk-generator/tree/1.5.3" + "source": "https://github.com/appwrite/sdk-generator/tree/1.5.5" }, - "time": "2025-11-10T09:50:41+00:00" + "time": "2025-11-14T05:56:33+00:00" }, { "name": "doctrine/annotations", @@ -8718,16 +8718,16 @@ }, { "name": "theseer/tokenizer", - "version": "1.2.3", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", - "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/d74205c497bfbca49f34d4bc4c19c17e22db4ebb", + "reference": "d74205c497bfbca49f34d4bc4c19c17e22db4ebb", "shasum": "" }, "require": { @@ -8756,7 +8756,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + "source": "https://github.com/theseer/tokenizer/tree/1.3.0" }, "funding": [ { @@ -8764,7 +8764,7 @@ "type": "github" } ], - "time": "2024-03-03T12:36:25+00:00" + "time": "2025-11-13T13:44:09+00:00" }, { "name": "twig/twig",