Finalize PR, review changes, fix tests

This commit is contained in:
Matej Bačo
2025-03-08 16:50:39 +01:00
parent faa1b0a59b
commit 232f99c6c9
19 changed files with 396 additions and 171 deletions
+10 -28
View File
@@ -23,6 +23,8 @@ return [
'name' => 'Next.js',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/next-js/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/next-js/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -30,8 +32,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './.next',
'startCommand' => 'sh helpers/next-js/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/next-js/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/next-js/env.sh',
],
'static' => [
'key' => 'static',
@@ -39,8 +39,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './out',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
]
]
],
@@ -56,8 +54,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
'fallbackFile' => 'index.html'
]
]
@@ -67,6 +63,8 @@ return [
'name' => 'Nuxt',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/nuxt/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/nuxt/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -74,8 +72,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './.output',
'startCommand' => 'sh helpers/nuxt/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/nuxt/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/nuxt/env.sh',
],
'static' => [
'key' => 'static',
@@ -83,8 +79,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
]
]
],
@@ -100,8 +94,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
'fallbackFile' => 'index.html'
]
]
@@ -111,6 +103,8 @@ return [
'name' => 'SvelteKit',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/sveltekit/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/sveltekit/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -118,8 +112,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './build',
'startCommand' => 'sh helpers/sveltekit/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/sveltekit/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/sveltekit/env.sh',
],
'static' => [
'key' => 'static',
@@ -127,8 +119,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './build',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
]
]
],
@@ -137,6 +127,8 @@ return [
'name' => 'Astro',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/astro/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/astro/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -144,8 +136,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/astro/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/astro/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/astro/env.sh',
],
'static' => [
'key' => 'static',
@@ -153,8 +143,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './dist',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
]
]
],
@@ -163,6 +151,8 @@ return [
'name' => 'Remix',
'buildRuntime' => 'node-22',
'runtimes' => getVersions($templateRuntimes['NODE']['versions'], 'node'),
'bundleCommand' => 'sh /usr/local/server/helpers/remix/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/remix/env.sh',
'adapters' => [
'ssr' => [
'key' => 'ssr',
@@ -170,8 +160,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './build',
'startCommand' => 'sh helpers/remix/server.sh',
'bundleCommand' => 'sh /usr/local/server/helpers/remix/bundle.sh',
'envCommand' => 'source /usr/local/server/helpers/remix/env.sh',
],
'static' => [
'key' => 'static',
@@ -179,8 +167,6 @@ return [
'installCommand' => 'npm install',
'outputDirectory' => './build/client',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
]
]
],
@@ -196,8 +182,6 @@ return [
'installCommand' => '',
'outputDirectory' => './build/web',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
],
],
],
@@ -213,8 +197,6 @@ return [
'installCommand' => '',
'outputDirectory' => './',
'startCommand' => 'sh helpers/server.sh',
'bundleCommand' => '',
'envCommand' => '',
],
]
],
+51 -53
View File
@@ -606,7 +606,7 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories/:pro
App::post('/v1/vcs/github/installations/:installationId/detections')
->alias('/v1/vcs/github/installations/:installationId/providerRepositories/:providerRepositoryId/detection')
->desc('Detect runtime and framework settings from source code')
->desc('Create repository detection')
->groups(['api', 'vcs'])
->label('scope', 'vcs.write')
->label('sdk', new Method(
@@ -617,11 +617,11 @@ App::post('/v1/vcs/github/installations/:installationId/detections')
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_RUNTIME_DETECTION,
model: Response::MODEL_DETECTION_RUNTIME,
),
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_FRAMEWORK_DETECTION,
model: Response::MODEL_DETECTION_FRAMEWORK,
)
]
))
@@ -663,20 +663,20 @@ App::post('/v1/vcs/github/installations/:installationId/detections')
->addOption(new Yarn())
->addOption(new PNPM())
->addOption(new NPM());
$detectedPackager = $detector->detect();
$detection = $detector->detect();
$packagerName = !\is_null($detectedPackager) ? $detectedPackager->getName() : 'npm';
$packager = !\is_null($detection) ? $detection->getName() : 'npm';
if ($type === 'framework') {
$detection = new Document([
$output = new Document([
'framework' => '',
'installCommand' => '',
'buildCommand' => '',
'outputDirectory' => '',
]);
$frameworkDetector = new Framework($files, $packagerName);
$frameworkDetector
$detector = new Framework($files, $packager);
$detector
->addOption(new Flutter())
->addOption(new Nuxt())
->addOption(new Astro())
@@ -684,28 +684,27 @@ App::post('/v1/vcs/github/installations/:installationId/detections')
->addOption(new SvelteKit())
->addOption(new NextJs());
$detectedFramework = $frameworkDetector->detect();
$framework = $detector->detect();
if ($detectedFramework) {
$framework = $detectedFramework->getName();
$detection->setAttribute('installCommand', $detectedFramework->getInstallCommand());
$detection->setAttribute('buildCommand', $detectedFramework->getBuildCommand());
$detection->setAttribute('outputDirectory', $detectedFramework->getOutputDirectory());
if (!\is_null($framework)) {
$framework = $framework->getName();
$output->setAttribute('installCommand', $framework->getInstallCommand());
$output->setAttribute('buildCommand', $framework->getBuildCommand());
$output->setAttribute('outputDirectory', $framework->getOutputDirectory());
} else {
$framework = 'other';
$detection->setAttribute('installCommand', '');
$detection->setAttribute('buildCommand', '');
$detection->setAttribute('outputDirectory', '');
$output->setAttribute('installCommand', '');
$output->setAttribute('buildCommand', '');
$output->setAttribute('outputDirectory', '');
}
$frameworks = Config::getParam('frameworks');
$frameworkKey = 'other';
if (\in_array($framework, array_keys($frameworks), true)) {
$frameworkKey = $framework;
if (!\in_array($framework, array_keys($frameworks), true)) {
$framework = 'other';
}
$detection->setAttribute('framework', $frameworkKey);
$output->setAttribute('framework', $framework);
} else {
$detection = new Document([
$output = new Document([
'runtime' => '',
'commands' => '',
'entrypoint' => '',
@@ -718,8 +717,8 @@ App::post('/v1/vcs/github/installations/:installationId/detections')
];
foreach ($strategies as $strategy) {
$runtimeDetector = new Runtime($strategy === Strategy::LANGUAGES ? $languages : $files, $strategy, $packagerName);
$runtimeDetector
$detector = new Runtime($strategy === Strategy::LANGUAGES ? $languages : $files, $strategy, $packager);
$detector
->addOption(new Node())
->addOption(new Bun())
->addOption(new Deno())
@@ -732,35 +731,35 @@ App::post('/v1/vcs/github/installations/:installationId/detections')
->addOption(new CPP())
->addOption(new Dotnet());
$detectedRuntime = $runtimeDetector->detect();
$runtime = $detector->detect();
if ($detectedRuntime) {
$detection->setAttribute('commands', $detectedRuntime->getCommands());
$detection->setAttribute('entrypoint', $detectedRuntime->getEntrypoint());
$runtime = $detectedRuntime->getName();
if (!\is_null($runtime)) {
$output->setAttribute('commands', $runtime->getCommands());
$output->setAttribute('entrypoint', $runtime->getEntrypoint());
$runtime = $runtime->getName();
break;
}
}
if (!empty($runtime)) {
$runtimes = Config::getParam('runtimes');
$versionedRuntime = '';
$runtimeWithVersion = '';
foreach ($runtimes as $runtimeKey => $runtimeConfig) {
if ($runtimeConfig['key'] === $runtime) {
$versionedRuntime = $runtimeKey;
$runtimeWithVersion = $runtimeKey;
}
}
if (empty($versionedRuntime)) {
if (empty($runtimeWithVersion)) {
throw new Exception(Exception::FUNCTION_RUNTIME_NOT_DETECTED);
}
$detection->setAttribute('runtime', $versionedRuntime);
$output->setAttribute('runtime', $runtimeWithVersion);
} else {
throw new Exception(Exception::FUNCTION_RUNTIME_NOT_DETECTED);
}
}
$response->dynamic($detection, $type === 'framework' ? Response::MODEL_FRAMEWORK_DETECTION : Response::MODEL_RUNTIME_DETECTION);
$response->dynamic($output, $type === 'framework' ? Response::MODEL_DETECTION_FRAMEWORK : Response::MODEL_DETECTION_RUNTIME);
});
App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
@@ -775,11 +774,11 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_RUNTIME_PROVIDER_REPOSITORY_LIST,
model: Response::MODEL_PROVIDER_REPOSITORY_RUNTIME_LIST,
),
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_FRAMEWORK_PROVIDER_REPOSITORY_LIST,
model: Response::MODEL_PROVIDER_REPOSITORY_FRAMEWORK_LIST,
)
]
))
@@ -829,12 +828,12 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
->addOption(new Yarn())
->addOption(new PNPM())
->addOption(new NPM());
$detectedPackager = $detector->detect();
$detection = $detector->detect();
$packagerName = !\is_null($detectedPackager) ? $detectedPackager->getName() : 'npm';
$packager = !\is_null($detection) ? $detection->getName() : 'npm';
if ($type === 'framework') {
$frameworkDetector = new Framework($files, $packagerName);
$frameworkDetector = new Framework($files, $packager);
$frameworkDetector
->addOption(new Flutter())
->addOption(new Nuxt())
@@ -845,18 +844,17 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
$detectedFramework = $frameworkDetector->detect();
if ($detectedFramework) {
if (!\is_null($detectedFramework)) {
$framework = $detectedFramework->getName();
} else {
$framework = 'other';
}
$frameworks = Config::getParam('frameworks');
$frameworkKey = '';
if (\in_array($framework, array_keys($frameworks), true)) {
$frameworkKey = $framework;
if (!\in_array($framework, array_keys($frameworks), true)) {
$framework = 'other';
}
$repo['framework'] = !empty($frameworkKey) ? $frameworkKey : 'other';
$repo['framework'] = $framework;
} else {
$languages = $github->listRepositoryLanguages($repo['organization'], $repo['name']);
@@ -867,8 +865,8 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
];
foreach ($strategies as $strategy) {
$runtimeDetector = new Runtime($strategy === Strategy::LANGUAGES ? $languages : $files, $strategy, $packagerName);
$runtimeDetector
$redector = new Runtime($strategy === Strategy::LANGUAGES ? $languages : $files, $strategy, $packager);
$redector
->addOption(new Node())
->addOption(new Bun())
->addOption(new Deno())
@@ -881,24 +879,24 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
->addOption(new CPP())
->addOption(new Dotnet());
$detectedRuntime = $runtimeDetector->detect();
$runtime = $redector->detect();
if ($detectedRuntime) {
$runtime = $detectedRuntime->getName();
if (!\is_null($runtime)) {
$runtime = $runtime->getName();
break;
}
}
if (!empty($runtime)) {
$runtimes = Config::getParam('runtimes');
$versionedRuntime = '';
$runtimeWithVersion = '';
foreach ($runtimes as $runtimeKey => $runtimeConfig) {
if ($runtimeConfig['key'] === $runtime) {
$versionedRuntime = $runtimeKey;
$runtimeWithVersion = $runtimeKey;
}
}
$repo['runtime'] = $versionedRuntime ?? '';
$repo['runtime'] = $runtimeWithVersion ?? '';
}
}
return $repo;
@@ -912,7 +910,7 @@ App::get('/v1/vcs/github/installations/:installationId/providerRepositories')
$response->dynamic(new Document([
$type === 'framework' ? 'frameworkProviderRepositories' : 'runtimeProviderRepositories' => $repos,
'total' => \count($repos),
]), ($type === 'framework') ? Response::MODEL_FRAMEWORK_PROVIDER_REPOSITORY_LIST : Response::MODEL_RUNTIME_PROVIDER_REPOSITORY_LIST);
]), ($type === 'framework') ? Response::MODEL_PROVIDER_REPOSITORY_FRAMEWORK_LIST : Response::MODEL_PROVIDER_REPOSITORY_RUNTIME_LIST);
});
App::post('/v1/vcs/github/installations/:installationId/providerRepositories')
Generated
+75 -3
View File
@@ -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": "3b6171de8c624cfbcd723f1cc76a9560",
"content-hash": "34ca1e0386c2325732532c6978cd93fb",
"packages": [
{
"name": "adhocore/jwt",
@@ -3758,6 +3758,69 @@
},
"time": "2025-02-12T08:08:29+00:00"
},
{
"name": "utopia-php/detector",
"version": "dev-feat-pseudocode-draft2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/detector.git",
"reference": "e843ff2c85ed55e2cbe7e29f11583903fe002774"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/detector/zipball/e843ff2c85ed55e2cbe7e29f11583903fe002774",
"reference": "e843ff2c85ed55e2cbe7e29f11583903fe002774",
"shasum": ""
},
"require": {
"php": ">=8.0"
},
"require-dev": {
"laravel/pint": "1.2.*",
"phpstan/phpstan": "1.8.*",
"phpunit/phpunit": "^9.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Utopia\\Detector\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Utopia\\Tests\\": "tests/Detector/"
}
},
"scripts": {
"lint": [
"./vendor/bin/pint --test --config pint.json"
],
"format": [
"./vendor/bin/pint --config pint.json"
],
"check": [
"./vendor/bin/phpstan analyse --level 8 -c phpstan.neon src tests"
],
"test": [
"./vendor/bin/phpunit --configuration phpunit.xml --debug"
]
},
"license": [
"MIT"
],
"description": "A simple library for fast and reliable environment identification.",
"keywords": [
"detector",
"framework",
"php",
"utopia"
],
"support": {
"source": "https://github.com/utopia-php/detector/tree/feat-pseudocode-draft2",
"issues": "https://github.com/utopia-php/detector/issues"
},
"time": "2025-03-08T15:32:38+00:00"
},
{
"name": "utopia-php/domains",
"version": "0.5.0",
@@ -8793,9 +8856,18 @@
"time": "2024-03-07T20:33:40+00:00"
}
],
"aliases": [],
"aliases": [
{
"package": "utopia-php/detector",
"version": "dev-feat-pseudocode-draft2",
"alias": "0.1.99",
"alias_normalized": "0.1.99.0"
}
],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"utopia-php/detector": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
+1 -1
View File
@@ -976,7 +976,7 @@ services:
# It's not possible to share mount file between 2 containers without host mount (copying is too slow)
- /tmp:/tmp:rw
environment:
- OPR_EXECUTOR_IMAGE_PULL=enabled
- OPR_EXECUTOR_IMAGE_PULL=disabled
- OPR_EXECUTOR_INACTIVE_TRESHOLD=$_APP_COMPUTE_INACTIVE_THRESHOLD
- OPR_EXECUTOR_MAINTENANCE_INTERVAL=$_APP_COMPUTE_MAINTENANCE_INTERVAL
- OPR_EXECUTOR_NETWORK=$_APP_COMPUTE_RUNTIMES_NETWORK
@@ -610,7 +610,7 @@ class Builds extends Action
memory: $memory,
timeout: $timeout,
remove: false,
entrypoint: $deployment->getAttribute('entrypoint', 'package.json'), // TODO: change this later so that sites don't need to have an entrypoint
entrypoint: $deployment->getAttribute('entrypoint', ''),
destination: APP_STORAGE_BUILDS . "/app-{$project->getId()}",
variables: $vars,
command: $command,
@@ -711,30 +711,32 @@ class Builds extends Action
}
if ($resource->getCollection() === 'sites' && isEmpty($resource->getAttribute('adapter'))) {
$listFilesCommand = "cd /usr/local/build/" . $resource->getAttribute('outputDirectory') . " && find . -name 'node_modules' -prune -o -type f -print";
$commandExecutionResponse = $executor->executeCommand(
$listFilesCommand = "cd /usr/local/build && cd " . \escapeshellarg($resource->getAttribute('outputDirectory')) . " && find . -name 'node_modules' -prune -o -type f -print";
$command = $executor->createCommand(
deploymentId: $deployment->getId(),
projectId: $project->getId(),
command: $listFilesCommand,
timeout: 60
timeout: 15
);
$files = array_map('trim', array_filter(explode("\n", $commandExecutionResponse['output'])));
$files = \explode("\n", $command['output']); // Parse output
$files = \array_filter($files); // Remove empty
$files = \array_map(fn ($file) => \trim($file), $files); // Remove whitepsaces
$files = \array_map(fn ($file) => \str_starts_with($file, './') ? \substr($file, 2) : $file, $files); // Remove beginning ./
$detector = new Rendering($files, $resource->getAttribute('framework'));
$detector = new Rendering($files, $resource->getAttribute('framework', ''));
$detector
->addOption(new SSR())
->addOption(new XStatic());
$detectedRenderingStrategy = $detector->detect();
$detection = $detector->detect();
$renderingStrategy = $detectedRenderingStrategy->getName();
$fallbackFile = $detectedRenderingStrategy->getFallbackFile() ?: '';
$resource->setAttribute('adapter', $renderingStrategy);
$resource->setAttribute('fallbackFile', $fallbackFile);
$resource->setAttribute('adapter', $detection->getName());
$resource->setAttribute('fallbackFile', $detection->getFallbackFile() ?? '');
$resource = $dbForProject->updateDocument('sites', $resource->getId(), $resource);
}
$executor->deleteRuntime($project->getId(), $deployment->getId(), '-build');
/** Update the build document */
$build->setAttribute('startTime', DateTime::format((new \DateTime())->setTimestamp(floor($response['startTime']))));
$build->setAttribute('endTime', $endTime);
@@ -1072,15 +1074,9 @@ class Builds extends Action
$envCommand = '';
$bundleCommand = '';
if (!is_null($framework)) {
$adapter = ($framework['adapters'] ?? [])[$resource->getAttribute('adapter', '')] ?? null;
if (!is_null($adapter) && isset($adapter['envCommand'])) {
$envCommand = $adapter['envCommand'];
}
if (!is_null($adapter) && isset($adapter['bundleCommand'])) {
$bundleCommand = $adapter['bundleCommand'];
}
$envCommand = $framework['envCommand'] ?? '';
$bundleCommand = $framework['bundleCommand'] ?? '';
}
$commands[] = $envCommand;
@@ -91,7 +91,7 @@ class Create extends Base
->callback([$this, 'action']);
}
public function action(string $siteId, string $name, string $framework, bool $enabled, int $timeout, string $installCommand, string $buildCommand, string $outputDirectory, string $buildRuntime, string $adapter, string $installationId, ?string $fallbackFile, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $specification, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Database $dbForPlatform)
public function action(string $siteId, string $name, string $framework, bool $enabled, int $timeout, string $installCommand, string $buildCommand, string $outputDirectory, string $buildRuntime, string $adapter, string $installationId, string $fallbackFile, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $specification, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Database $dbForPlatform)
{
if (!empty($adapter)) {
$configFramework = Config::getParam('frameworks')[$framework] ?? [];
@@ -98,7 +98,7 @@ class Update extends Base
->callback([$this, 'action']);
}
public function action(string $siteId, string $name, string $framework, bool $enabled, int $timeout, string $installCommand, string $buildCommand, string $outputDirectory, string $buildRuntime, string $adapter, ?string $fallbackFile, string $installationId, ?string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $specification, Request $request, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Build $queueForBuilds, Database $dbForPlatform, GitHub $github)
public function action(string $siteId, string $name, string $framework, bool $enabled, int $timeout, string $installCommand, string $buildCommand, string $outputDirectory, string $buildRuntime, string $adapter, string $fallbackFile, string $installationId, ?string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $specification, Request $request, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Build $queueForBuilds, Database $dbForPlatform, GitHub $github)
{
if (!empty($adapter)) {
$configFramework = Config::getParam('frameworks')[$framework] ?? [];
+16 -16
View File
@@ -38,6 +38,8 @@ use Appwrite\Utopia\Response\Model\Country;
use Appwrite\Utopia\Response\Model\Currency;
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\Document as ModelDocument;
use Appwrite\Utopia\Response\Model\Error;
use Appwrite\Utopia\Response\Model\ErrorDev;
@@ -45,8 +47,6 @@ use Appwrite\Utopia\Response\Model\Execution;
use Appwrite\Utopia\Response\Model\File;
use Appwrite\Utopia\Response\Model\Framework;
use Appwrite\Utopia\Response\Model\FrameworkAdapter;
use Appwrite\Utopia\Response\Model\FrameworkDetection;
use Appwrite\Utopia\Response\Model\FrameworkProviderRepository;
use Appwrite\Utopia\Response\Model\Func;
use Appwrite\Utopia\Response\Model\Headers;
use Appwrite\Utopia\Response\Model\HealthAntivirus;
@@ -84,10 +84,10 @@ use Appwrite\Utopia\Response\Model\Preferences;
use Appwrite\Utopia\Response\Model\Project;
use Appwrite\Utopia\Response\Model\Provider;
use Appwrite\Utopia\Response\Model\ProviderRepository;
use Appwrite\Utopia\Response\Model\ProviderRepositoryFramework;
use Appwrite\Utopia\Response\Model\ProviderRepositoryRuntime;
use Appwrite\Utopia\Response\Model\Rule;
use Appwrite\Utopia\Response\Model\Runtime;
use Appwrite\Utopia\Response\Model\RuntimeDetection;
use Appwrite\Utopia\Response\Model\RuntimeProviderRepository;
use Appwrite\Utopia\Response\Model\Session;
use Appwrite\Utopia\Response\Model\Site;
use Appwrite\Utopia\Response\Model\Specification;
@@ -250,14 +250,14 @@ class Response extends SwooleResponse
public const MODEL_INSTALLATION_LIST = 'installationList';
public const MODEL_PROVIDER_REPOSITORY = 'providerRepository';
public const MODEL_PROVIDER_REPOSITORY_LIST = 'providerRepositoryList';
public const MODEL_FRAMEWORK_PROVIDER_REPOSITORY = 'frameworkProviderRepository';
public const MODEL_FRAMEWORK_PROVIDER_REPOSITORY_LIST = 'frameworkProviderRepositoryList';
public const MODEL_RUNTIME_PROVIDER_REPOSITORY = 'runtimeProviderRepository';
public const MODEL_RUNTIME_PROVIDER_REPOSITORY_LIST = 'runtimeProviderRepositoryList';
public const MODEL_PROVIDER_REPOSITORY_FRAMEWORK = 'providerRepositoryFramework';
public const MODEL_PROVIDER_REPOSITORY_FRAMEWORK_LIST = 'providerRepositoryFrameworkList';
public const MODEL_PROVIDER_REPOSITORY_RUNTIME = 'providerRepositoryRuntime';
public const MODEL_PROVIDER_REPOSITORY_RUNTIME_LIST = 'providerRepositoryRuntimeList';
public const MODEL_BRANCH = 'branch';
public const MODEL_BRANCH_LIST = 'branchList';
public const MODEL_FRAMEWORK_DETECTION = 'frameworkDetection';
public const MODEL_RUNTIME_DETECTION = 'runtimeDetection';
public const MODEL_DETECTION_FRAMEWORK = 'detectionFramework';
public const MODEL_DETECTION_RUNTIME = 'detectionRuntime';
public const MODEL_VCS_CONTENT = 'vcsContent';
public const MODEL_VCS_CONTENT_LIST = 'vcsContentList';
@@ -383,8 +383,8 @@ class Response extends SwooleResponse
->setModel(new BaseList('Functions List', self::MODEL_FUNCTION_LIST, 'functions', self::MODEL_FUNCTION))
->setModel(new BaseList('Function Templates List', self::MODEL_TEMPLATE_FUNCTION_LIST, 'templates', self::MODEL_TEMPLATE_FUNCTION))
->setModel(new BaseList('Installations List', self::MODEL_INSTALLATION_LIST, 'installations', self::MODEL_INSTALLATION))
->setModel(new BaseList('Framework Provider Repositories List', self::MODEL_FRAMEWORK_PROVIDER_REPOSITORY_LIST, 'frameworkProviderRepositories', self::MODEL_FRAMEWORK_PROVIDER_REPOSITORY))
->setModel(new BaseList('Runtime Provider Repositories List', self::MODEL_RUNTIME_PROVIDER_REPOSITORY_LIST, 'runtimeProviderRepositories', self::MODEL_RUNTIME_PROVIDER_REPOSITORY))
->setModel(new BaseList('Framework Provider Repositories List', self::MODEL_PROVIDER_REPOSITORY_FRAMEWORK_LIST, 'frameworkProviderRepositories', self::MODEL_PROVIDER_REPOSITORY_FRAMEWORK))
->setModel(new BaseList('Runtime Provider Repositories List', self::MODEL_PROVIDER_REPOSITORY_RUNTIME_LIST, 'runtimeProviderRepositories', self::MODEL_PROVIDER_REPOSITORY_RUNTIME))
->setModel(new BaseList('Branches List', self::MODEL_BRANCH_LIST, 'branches', self::MODEL_BRANCH))
->setModel(new BaseList('Frameworks List', self::MODEL_FRAMEWORK_LIST, 'frameworks', self::MODEL_FRAMEWORK))
->setModel(new BaseList('Runtimes List', self::MODEL_RUNTIME_LIST, 'runtimes', self::MODEL_RUNTIME))
@@ -462,10 +462,10 @@ class Response extends SwooleResponse
->setModel(new TemplateVariable())
->setModel(new Installation())
->setModel(new ProviderRepository())
->setModel(new FrameworkProviderRepository())
->setModel(new RuntimeProviderRepository())
->setModel(new FrameworkDetection())
->setModel(new RuntimeDetection())
->setModel(new ProviderRepositoryFramework())
->setModel(new ProviderRepositoryRuntime())
->setModel(new DetectionFramework())
->setModel(new DetectionRuntime())
->setModel(new VcsContent())
->setModel(new Branch())
->setModel(new Runtime())
@@ -5,7 +5,7 @@ namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
class FrameworkDetection extends Model
class DetectionFramework extends Model
{
public function __construct()
{
@@ -43,7 +43,7 @@ class FrameworkDetection extends Model
*/
public function getName(): string
{
return 'FrameworkDetection';
return 'DetectionFramework';
}
/**
@@ -53,6 +53,6 @@ class FrameworkDetection extends Model
*/
public function getType(): string
{
return Response::MODEL_FRAMEWORK_DETECTION;
return Response::MODEL_DETECTION_FRAMEWORK;
}
}
@@ -5,7 +5,7 @@ namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
use Appwrite\Utopia\Response\Model;
class RuntimeDetection extends Model
class DetectionRuntime extends Model
{
public function __construct()
{
@@ -37,7 +37,7 @@ class RuntimeDetection extends Model
*/
public function getName(): string
{
return 'RuntimeDetection';
return 'DetectionRuntime';
}
/**
@@ -47,6 +47,6 @@ class RuntimeDetection extends Model
*/
public function getType(): string
{
return Response::MODEL_RUNTIME_DETECTION;
return Response::MODEL_DETECTION_RUNTIME;
}
}
@@ -4,7 +4,7 @@ namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
class FrameworkProviderRepository extends ProviderRepository
class ProviderRepositoryFramework extends ProviderRepository
{
public function __construct()
{
@@ -12,7 +12,7 @@ class FrameworkProviderRepository extends ProviderRepository
$this->addRule('framework', [
'type' => self::TYPE_STRING,
'description' => 'Auto-detected framework suggestion. Empty if getting response of getFramework().',
'description' => 'Auto-detected framework. Empty if type is not "framework".',
'default' => '',
'example' => 'nextjs',
]);
@@ -25,7 +25,7 @@ class FrameworkProviderRepository extends ProviderRepository
*/
public function getName(): string
{
return 'FrameworkProviderRepository';
return 'ProviderRepositoryFramework';
}
/**
@@ -35,6 +35,6 @@ class FrameworkProviderRepository extends ProviderRepository
*/
public function getType(): string
{
return Response::MODEL_FRAMEWORK_PROVIDER_REPOSITORY;
return Response::MODEL_PROVIDER_REPOSITORY_FRAMEWORK;
}
}
@@ -4,7 +4,7 @@ namespace Appwrite\Utopia\Response\Model;
use Appwrite\Utopia\Response;
class RuntimeProviderRepository extends ProviderRepository
class ProviderRepositoryRuntime extends ProviderRepository
{
public function __construct()
{
@@ -12,9 +12,9 @@ class RuntimeProviderRepository extends ProviderRepository
$this->addRule('runtime', [
'type' => self::TYPE_STRING,
'description' => 'Auto-detected runtime suggestion. Empty if getting response of getRuntime().',
'description' => 'Auto-detected runtime. Empty if type is not "runtime".',
'default' => '',
'example' => 'node',
'example' => 'node-22',
]);
}
@@ -25,7 +25,7 @@ class RuntimeProviderRepository extends ProviderRepository
*/
public function getName(): string
{
return 'RuntimeProviderRepository';
return 'ProviderRepositoryRuntime';
}
/**
@@ -35,6 +35,6 @@ class RuntimeProviderRepository extends ProviderRepository
*/
public function getType(): string
{
return Response::MODEL_RUNTIME_PROVIDER_REPOSITORY;
return Response::MODEL_PROVIDER_REPOSITORY_RUNTIME;
}
}
+3 -3
View File
@@ -135,9 +135,9 @@ class Executor
* @param string $projectId
* @param string $deploymentId
*/
public function deleteRuntime(string $projectId, string $deploymentId)
public function deleteRuntime(string $projectId, string $deploymentId, string $suffix = '')
{
$runtimeId = "$projectId-$deploymentId";
$runtimeId = "$projectId-$deploymentId" . $suffix;
$route = "/runtimes/$runtimeId";
$response = $this->call(self::METHOD_DELETE, $route, [
@@ -249,7 +249,7 @@ class Executor
return $response['body'];
}
public function executeCommand(
public function createCommand(
string $deploymentId,
string $projectId,
string $command,
@@ -362,40 +362,168 @@ class SitesCustomServerTest extends Scope
$this->cleanupSite($siteId);
}
public function testRenderingDetectionSSR(): void
public function testAdapterDetectionAstroSSR(): void
{
$siteId = $this->setupSite([
'siteId' => ID::unique(),
'name' => 'Astro site',
'name' => 'Astro SSR site',
'framework' => 'astro',
'buildRuntime' => 'ssr-22',
'buildRuntime' => 'node-22',
'outputDirectory' => './dist',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
]);
$this->assertNotEmpty($siteId);
$site = $this->getSite($siteId);
$this->assertEquals('200', $site['headers']['status-code']);
$this->assertArrayHasKey('adapter', $site['body']);
$this->assertEmpty($site['body']['adapter']);
$domain = $this->setupSiteDomain($siteId);
$this->assertNotEmpty($domain);
$deploymentId = $this->setupDeployment($siteId, [
'code' => $this->packageSite('astro'),
'activate' => 'true'
]);
$this->assertNotEmpty($deploymentId);
$domain = $this->getSiteDomain($siteId);
$site = $this->getSite($siteId);
$this->assertEquals('ssr', $site['body']['adapter']);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/');
$this->assertEquals(200, $response['headers']['status-code']);
$this->cleanupSite($siteId);
}
public function testAdapterDetectionAstroStatic(): void
{
$siteId = $this->setupSite([
'siteId' => ID::unique(),
'name' => 'Astro static site',
'framework' => 'astro',
'buildRuntime' => 'node-22',
'outputDirectory' => './dist',
'buildCommand' => 'npm run build',
'installCommand' => 'npm install',
]);
$this->assertNotEmpty($siteId);
$site = $this->getSite($siteId);
$this->assertEquals('200', $site['headers']['status-code']);
$this->assertArrayHasKey('adapter', $site['body']);
$this->assertEmpty($site['body']['adapter']);
$domain = $this->setupSiteDomain($siteId);
$this->assertNotEmpty($domain);
$deploymentId = $this->setupDeployment($siteId, [
'code' => $this->packageSite('astro-static'),
'activate' => 'true'
]);
$this->assertNotEmpty($deploymentId);
$site = $this->getSite($siteId);
$this->assertEquals('200', $site['headers']['status-code']);
$this->assertEquals('static', $site['body']['adapter']);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/');
$this->assertEquals(200, $response['headers']['status-code']);
$this->cleanupSite($siteId);
}
public function testAdapterDetectionStatic(): void
{
$siteId = $this->setupSite([
'siteId' => ID::unique(),
'name' => 'Static site',
'framework' => 'other',
'buildRuntime' => 'node-22',
'outputDirectory' => '',
'buildCommand' => '',
'installCommand' => '',
]);
$this->assertNotEmpty($siteId);
$site = $this->getSite($siteId);
$this->assertEquals('200', $site['headers']['status-code']);
$this->assertArrayHasKey('adapter', $site['body']);
$this->assertEmpty($site['body']['adapter']);
$domain = $this->setupSiteDomain($siteId);
$this->assertNotEmpty($domain);
$deploymentId = $this->setupDeployment($siteId, [
'code' => $this->packageSite('static'),
'activate' => 'true'
]);
$this->assertNotEmpty($deploymentId);
$site = $this->getSite($siteId);
$this->assertEquals('200', $site['headers']['status-code']);
$this->assertEquals('static', $site['body']['adapter']);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/');
$this->assertEquals(200, $response['headers']['status-code']);
$this->cleanupSite($siteId);
}
public function testAdapterDetectionStaticSPA(): void
{
$siteId = $this->setupSite([
'siteId' => ID::unique(),
'name' => 'Static site',
'framework' => 'other',
'buildRuntime' => 'node-22',
'outputDirectory' => '',
'buildCommand' => '',
'installCommand' => '',
]);
$this->assertNotEmpty($siteId);
$site = $this->getSite($siteId);
$this->assertEquals('200', $site['headers']['status-code']);
$this->assertArrayHasKey('adapter', $site['body']);
$this->assertArrayHasKey('fallbackFile', $site['body']);
$this->assertEmpty($site['body']['adapter']);
$this->assertEmpty($site['body']['fallbackFile']);
$domain = $this->setupSiteDomain($siteId);
$this->assertNotEmpty($domain);
$deploymentId = $this->setupDeployment($siteId, [
'code' => $this->packageSite('static-single-file'),
'activate' => 'true'
]);
$this->assertNotEmpty($deploymentId);
$site = $this->getSite($siteId);
$this->assertEquals('200', $site['headers']['status-code']);
$this->assertEquals('static', $site['body']['adapter']);
$this->assertEquals('main.html', $site['body']['fallbackFile']);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/');
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('Main page', $response['body']);
$response = $proxyClient->call(Client::METHOD_GET, '/something');
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('Main page', $response['body']);
$this->cleanupSite($siteId);
}
public function testListSites(): void
{
/**
+33 -22
View File
@@ -154,7 +154,7 @@ class VCSConsoleClientTest extends Scope
* Test for FAILURE
*/
$framework = $this->client->call(Client::METHOD_POST, '/vcs/github/installations/' . $installationId . '/providerRepositories/randomRepositoryId/frameworks', array_merge([
$framework = $this->client->call(Client::METHOD_POST, '/vcs/github/installations/' . $installationId . '/detections', array_merge([
'x-appwrite-project' => $this->getProject()['$id'],
'content-type' => 'application/json',
], $this->getHeaders()), [
@@ -165,8 +165,6 @@ class VCSConsoleClientTest extends Scope
$this->assertEquals(404, $framework['headers']['status-code']);
}
// TODO: Change search to provideScenarios
/**
* @depends testGitHubAuthorize
*/
@@ -248,7 +246,6 @@ class VCSConsoleClientTest extends Scope
* Test for SUCCESS
*/
//runtimes
$repositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -262,28 +259,39 @@ class VCSConsoleClientTest extends Scope
$this->assertEquals($repositories['body']['runtimeProviderRepositories'][0]['provider'], 'github');
$this->assertEquals($repositories['body']['runtimeProviderRepositories'][0]['runtime'], 'node-22');
$this->assertEquals($repositories['body']['runtimeProviderRepositories'][1]['name'], 'templates-for-functions');
$this->assertEquals($repositories['body']['runtimeProviderRepositories'][1]['runtime'], '');
$this->assertEquals($repositories['body']['runtimeProviderRepositories'][2]['name'], 'function1.4');
$this->assertEquals($repositories['body']['runtimeProviderRepositories'][2]['runtime'], 'node-22');
$this->assertEquals($repositories['body']['runtimeProviderRepositories'][3]['name'], 'appwrite');
$this->assertEquals($repositories['body']['runtimeProviderRepositories'][3]['runtime'], 'php-8.3');
$searchedRepositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'function1.4',
'type' => 'runtime'
]);
$this->assertEquals(200, $searchedRepositories['headers']['status-code']);
$this->assertEquals($searchedRepositories['body']['total'], 1);
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['name'], 'function1.4');
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['runtime'], 'node-2');
$searchedRepositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'rub',
'search' => 'appwrite',
'type' => 'runtime'
]);
$this->assertEquals(200, $searchedRepositories['headers']['status-code']);
$this->assertEquals($searchedRepositories['body']['total'], 1);
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['name'], 'appwrite');
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['runtime'], 'php-8.3');
$searchedRepositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'ruby-starter',
'type' => 'runtime'
]);
$this->assertEquals(200, $searchedRepositories['headers']['status-code']);
$this->assertEquals($searchedRepositories['body']['total'], 1);
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['name'], 'ruby-starter');
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['runtime'], 'ruby-3.3');
// frameworks
$repositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
@@ -292,20 +300,23 @@ class VCSConsoleClientTest extends Scope
$this->assertEquals(200, $repositories['headers']['status-code']);
$this->assertEquals($repositories['body']['total'], 4);
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][0]['name'], 'starter-for-svelte');
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][0]['organization'], 'appwrite-test');
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][0]['provider'], 'github');
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][0]['framework'], 'sveltekit');
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][1]['name'], 'templates-for-functions');
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][1]['framework'], 'other');
$searchedRepositories = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories', array_merge([
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'search' => 'appwrite',
'type' => 'runtime'
]);
$this->assertEquals(200, $searchedRepositories['headers']['status-code']);
$this->assertEquals($searchedRepositories['body']['total'], 1);
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['name'], 'appwrite');
$this->assertEquals($searchedRepositories['body']['runtimeProviderRepositories'][0]['runtime'], 'other');
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][2]['name'], 'function1.4');
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][2]['framework'], 'other');
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][3]['name'], 'appwrite');
$this->assertEquals($repositories['body']['frameworkProviderRepositories'][3]['framework'], 'other');
// TODO: If you are about to add another check, rewrite this to @provideScenarios
/**
* Test for FAILURE
@@ -0,0 +1,4 @@
import { defineConfig } from 'astro/config';
export default defineConfig({
});
@@ -0,0 +1,14 @@
{
"name": "my-astro-app",
"type": "module",
"version": "0.0.1",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"astro": "^5.2.5"
}
}
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Astro static</title>
</head>
<body>
</body>
</html>
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Main page</title>
</head>
<body>
</body>
</html>