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'], ]); }