diff --git a/composer.lock b/composer.lock index 8303949120..7f589bf171 100644 --- a/composer.lock +++ b/composer.lock @@ -8839,5 +8839,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.3.0" } diff --git a/src/Appwrite/Platform/Modules/Compute/Base.php b/src/Appwrite/Platform/Modules/Compute/Base.php index 9ea0ef86c5..1c3b9f2ede 100644 --- a/src/Appwrite/Platform/Modules/Compute/Base.php +++ b/src/Appwrite/Platform/Modules/Compute/Base.php @@ -19,7 +19,7 @@ use Utopia\VCS\Exception\RepositoryNotFound; class Base extends Action { - public function redeployVcsFunction(Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Build $queueForBuilds, Document $template, GitHub $github) + public function redeployVcsFunction(Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Build $queueForBuilds, Document $template, GitHub $github): Document { $deploymentId = ID::unique(); $entrypoint = $function->getAttribute('entrypoint', ''); @@ -91,9 +91,11 @@ class Base extends Action ->setResource($function) ->setDeployment($deployment) ->setTemplate($template); + + return $deployment; } - public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github) + public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github): Document { $deploymentId = ID::unique(); $providerInstallationId = $installation->getAttribute('providerInstallationId', ''); @@ -187,5 +189,7 @@ class Base extends Action ->setResource($site) ->setDeployment($deployment) ->setTemplate($template); + + return $deployment; } } diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php new file mode 100644 index 0000000000..5082c23db2 --- /dev/null +++ b/src/Appwrite/Platform/Modules/Functions/Http/Deployments/Template/Create.php @@ -0,0 +1,143 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) + ->setHttpPath('/v1/functions/:functionId/deployments/template') + ->desc('Create template deployment') + ->groups(['api', 'functions']) + ->label('scope', 'functions.write') + ->label('event', 'functions.[functionId].deployments.[deploymentId].create') + ->label('resourceType', RESOURCE_TYPE_FUNCTIONS) + ->label('audits.event', 'deployment.create') + ->label('audits.resource', 'function/{request.functionId}') + ->label('sdk', new Method( + namespace: 'functions', + name: 'createTemplateDeployment', + description: <<param('functionId', '', new UID(), 'Function ID.') + ->param('repository', '', new Text(128, 0), 'Repository name of the template.') + ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') + ->param('rootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.') + ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.') + ->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) + ->inject('request') + ->inject('response') + ->inject('dbForProject') + ->inject('dbForPlatform') + ->inject('queueForEvents') + ->inject('project') + ->inject('queueForBuilds') + ->inject('gitHub') + ->callback([$this, 'action']); + } + + public function action(string $functionId, string $repository, string $owner, string $rootDirectory, string $version, bool $activate, Request $request, Response $response, Database $dbForProject, Database $dbForPlatform, Event $queueForEvents, Document $project, Build $queueForBuilds, GitHub $github) + { + $function = $dbForProject->getDocument('functions', $functionId); + + if ($function->isEmpty()) { + throw new Exception(Exception::FUNCTION_NOT_FOUND); + } + + $template = new Document([ + 'repositoryName' => $repository, + 'ownerName' => $owner, + 'rootDirectory' => $rootDirectory, + 'version' => $version + ]); + + if (!empty($function->getAttribute('providerRepositoryId'))) { + $installation = $dbForPlatform->getDocument('installations', $function->getAttribute('installationId')); + + $deployment = $this->redeployVcsFunction($request, $function, $project, $installation, $dbForProject, $queueForBuilds, $template, $github); + + $queueForEvents + ->setParam('functionId', $function->getId()) + ->setParam('deploymentId', $deployment->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($deployment, Response::MODEL_DEPLOYMENT); + + return; + } + + $deploymentId = ID::unique(); + $deployment = $dbForProject->createDocument('deployments', new Document([ + '$id' => $deploymentId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'resourceId' => $function->getId(), + 'resourceInternalId' => $function->getInternalId(), + 'resourceType' => 'functions', + 'entrypoint' => $function->getAttribute('entrypoint', ''), + 'commands' => $function->getAttribute('commands', ''), + 'type' => 'manual', + 'search' => implode(' ', [$deploymentId, $function->getAttribute('entrypoint', '')]), + 'activate' => $activate, + ])); + + $queueForBuilds + ->setType(BUILD_TYPE_DEPLOYMENT) + ->setResource($function) + ->setDeployment($deployment) + ->setTemplate($template); + + $queueForEvents + ->setParam('functionId', $function->getId()) + ->setParam('deploymentId', $deployment->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($deployment, Response::MODEL_DEPLOYMENT); + } +} diff --git a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php index 9d89b7edf0..0bf08ea412 100644 --- a/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php +++ b/src/Appwrite/Platform/Modules/Functions/Http/Functions/Create.php @@ -2,7 +2,6 @@ namespace Appwrite\Platform\Modules\Functions\Http\Functions; -use Appwrite\Event\Build; use Appwrite\Event\Event; use Appwrite\Event\Validator\FunctionEvent; use Appwrite\Extend\Exception; @@ -29,14 +28,12 @@ use Utopia\Database\Validator\Authorization; use Utopia\Database\Validator\Roles; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; -use Utopia\Swoole\Request; use Utopia\System\System; use Utopia\Validator\ArrayList; use Utopia\Validator\Boolean; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; -use Utopia\VCS\Adapter\Git\GitHub; class Create extends Base { @@ -90,30 +87,22 @@ class Create extends Base ->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function.', true) ->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.', true) ->param('providerRootDirectory', '', new Text(128, 0), 'Path to function code in the linked repo.', true) - ->param('templateRepository', '', new Text(128, 0), 'Repository name of the template.', true) - ->param('templateOwner', '', new Text(128, 0), 'The name of the owner of the template.', true) - ->param('templateRootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.', true) - ->param('templateVersion', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true) ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new RuntimeSpecification( $plan, Config::getParam('runtime-specifications', []), App::getEnv('_APP_COMPUTE_CPUS', APP_COMPUTE_CPUS_DEFAULT), App::getEnv('_APP_COMPUTE_MEMORY', APP_COMPUTE_MEMORY_DEFAULT) ), 'Runtime specification for the function and builds.', true, ['plan']) - ->inject('request') ->inject('response') ->inject('dbForProject') ->inject('timelimit') ->inject('project') - ->inject('user') ->inject('queueForEvents') - ->inject('queueForBuilds') ->inject('dbForPlatform') - ->inject('gitHub') ->callback([$this, 'action']); } - public function action(string $functionId, string $name, string $runtime, array $execute, array $events, string $schedule, int $timeout, bool $enabled, bool $logging, string $entrypoint, string $commands, array $scopes, string $installationId, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $templateRepository, string $templateOwner, string $templateRootDirectory, string $templateVersion, string $specification, Request $request, Response $response, Database $dbForProject, callable $timelimit, Document $project, Document $user, Event $queueForEvents, Build $queueForBuilds, Database $dbForPlatform, GitHub $github) + public function action(string $functionId, string $name, string $runtime, array $execute, array $events, string $schedule, int $timeout, bool $enabled, bool $logging, string $entrypoint, string $commands, array $scopes, string $installationId, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $specification, Response $response, Database $dbForProject, callable $timelimit, Document $project, Event $queueForEvents, Database $dbForPlatform) { // Temporary abuse check @@ -153,20 +142,6 @@ class Create extends Base throw new Exception(Exception::FUNCTION_RUNTIME_UNSUPPORTED, 'Runtime "' . $runtime . '" is not supported'); } - // build from template - $template = new Document([]); - if ( - !empty($templateRepository) - && !empty($templateOwner) - && !empty($templateRootDirectory) - && !empty($templateVersion) - ) { - $template->setAttribute('repositoryName', $templateRepository) - ->setAttribute('ownerName', $templateOwner) - ->setAttribute('rootDirectory', $templateRootDirectory) - ->setAttribute('version', $templateVersion); - } - $installation = $dbForPlatform->getDocument('installations', $installationId); if (!empty($installationId) && $installation->isEmpty()) { @@ -254,36 +229,6 @@ class Create extends Base $function = $dbForProject->updateDocument('functions', $function->getId(), $function); - if (!empty($providerRepositoryId)) { - // Deploy VCS - $this->redeployVcsFunction($request, $function, $project, $installation, $dbForProject, $queueForBuilds, $template, $github); - } elseif (!$template->isEmpty()) { - // Deploy non-VCS from template - $deploymentId = ID::unique(); - $deployment = $dbForProject->createDocument('deployments', new Document([ - '$id' => $deploymentId, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - 'resourceId' => $function->getId(), - 'resourceInternalId' => $function->getInternalId(), - 'resourceType' => 'functions', - 'entrypoint' => $function->getAttribute('entrypoint', ''), - 'commands' => $function->getAttribute('commands', ''), - 'type' => 'manual', - 'search' => implode(' ', [$deploymentId, $function->getAttribute('entrypoint', '')]), - 'activate' => true, - ])); - - $queueForBuilds - ->setType(BUILD_TYPE_DEPLOYMENT) - ->setResource($function) - ->setDeployment($deployment) - ->setTemplate($template); - } - $functionsDomain = System::getEnv('_APP_DOMAIN_FUNCTIONS', ''); if (!empty($functionsDomain)) { $routeSubdomain = ID::unique(); diff --git a/src/Appwrite/Platform/Modules/Functions/Services/Http.php b/src/Appwrite/Platform/Modules/Functions/Services/Http.php index 6c74182776..141c4abb62 100644 --- a/src/Appwrite/Platform/Modules/Functions/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Functions/Services/Http.php @@ -3,6 +3,7 @@ namespace Appwrite\Platform\Modules\Functions\Services; use Appwrite\Platform\Modules\Functions\Http\Deployments\Create as CreateDeployment; +use Appwrite\Platform\Modules\Functions\Http\Deployments\Template\Create as CreateTemplateDeployment; use Appwrite\Platform\Modules\Functions\Http\Functions\Create as CreateFunction; use Appwrite\Platform\Modules\Functions\Http\Functions\Update as UpdateFunction; use Appwrite\Platform\Modules\Functions\Http\Functions\XList as ListFunctions; @@ -19,5 +20,6 @@ class Http extends Service $this->addAction(ListFunctions::getName(), new ListFunctions()); $this->addAction(ListRuntimes::getName(), new ListRuntimes()); $this->addAction(CreateDeployment::getName(), new CreateDeployment()); + $this->addAction(CreateTemplateDeployment::getName(), new CreateTemplateDeployment()); } } diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php new file mode 100644 index 0000000000..507397d70c --- /dev/null +++ b/src/Appwrite/Platform/Modules/Sites/Http/Deployments/Template/Create.php @@ -0,0 +1,165 @@ +setHttpMethod(Action::HTTP_REQUEST_METHOD_POST) + ->setHttpPath('/v1/sites/:siteId/deployments/template') + ->desc('Create deployment') + ->groups(['api', 'sites']) + ->label('scope', 'sites.write') + ->label('event', 'sites.[siteId].deployments.[deploymentId].create') + ->label('audits.event', 'deployment.create') + ->label('audits.resource', 'site/{request.siteId}') + ->label('sdk', new Method( + namespace: 'sites', + name: 'createTemplateDeployment', + description: <<param('siteId', '', new UID(), 'Site ID.') + ->param('repository', '', new Text(128, 0), 'Repository name of the template.') + ->param('owner', '', new Text(128, 0), 'The name of the owner of the template.') + ->param('rootDirectory', '', new Text(128, 0), 'Path to site code in the template repo.') + ->param('version', '', new Text(128, 0), 'Version (tag) for the repo linked to the site template.') + ->param('activate', false, new Boolean(), 'Automatically activate the deployment when it is finished building.', true) + ->inject('request') + ->inject('response') + ->inject('dbForProject') + ->inject('dbForPlatform') + ->inject('project') + ->inject('queueForEvents') + ->inject('queueForBuilds') + ->inject('gitHub') + ->callback([$this, 'action']); + } + + public function action(string $siteId, string $repository, string $owner, string $rootDirectory, string $version, bool $activate, Request $request, Response $response, Database $dbForProject, Database $dbForPlatform, Document $project, Event $queueForEvents, Build $queueForBuilds, GitHub $github) + { + $site = $dbForProject->getDocument('sites', $siteId); + + if ($site->isEmpty()) { + throw new Exception(Exception::SITE_NOT_FOUND); + } + + $template = new Document([ + 'repositoryName' => $repository, + 'ownerName' => $owner, + 'rootDirectory' => $rootDirectory, + 'version' => $version + ]); + + if (!empty($providerRepositoryId)) { + $installation = $dbForPlatform->getDocument('installations', $site->getAttribute('installationId')); + + $deployment = $this->redeployVcsSite($request, $site, $project, $installation, $dbForProject, $dbForPlatform, $queueForBuilds, $template, $github); + + $queueForEvents + ->setParam('siteId', $site->getId()) + ->setParam('deploymentId', $deployment->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($deployment, Response::MODEL_DEPLOYMENT); + + return; + } + + $deploymentId = ID::unique(); + $deployment = $dbForProject->createDocument('deployments', new Document([ + '$id' => $deploymentId, + '$permissions' => [ + Permission::read(Role::any()), + Permission::update(Role::any()), + Permission::delete(Role::any()), + ], + 'resourceId' => $site->getId(), + 'resourceInternalId' => $site->getInternalId(), + 'resourceType' => 'sites', + 'installCommand' => $site->getAttribute('installCommand', ''), + 'buildCommand' => $site->getAttribute('buildCommand', ''), + 'outputDirectory' => $site->getAttribute('outputDirectory', ''), + 'type' => 'manual', + 'search' => implode(' ', [$deploymentId]), + 'activate' => $activate, + ])); + + // Preview deployments url + $projectId = $project->getId(); + + $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); + $previewDomain = "{$deploymentId}-{$projectId}.{$sitesDomain}"; + + $rule = Authorization::skip( + fn () => $dbForPlatform->createDocument('rules', new Document([ + '$id' => \md5($previewDomain), + 'projectId' => $project->getId(), + 'projectInternalId' => $project->getInternalId(), + 'domain' => $previewDomain, + 'resourceType' => 'deployment', + 'resourceId' => $deploymentId, + 'resourceInternalId' => $deployment->getInternalId(), + 'status' => 'verified', + 'certificateId' => '', + ])) + ); + + $queueForBuilds + ->setType(BUILD_TYPE_DEPLOYMENT) + ->setResource($site) + ->setDeployment($deployment) + ->setTemplate($template); + + $queueForEvents + ->setParam('siteId', $site->getId()) + ->setParam('deploymentId', $deployment->getId()); + + $response + ->setStatusCode(Response::STATUS_CODE_ACCEPTED) + ->dynamic($deployment, Response::MODEL_DEPLOYMENT); + } +} diff --git a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php index 079f2fec49..52fa8e47a2 100644 --- a/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php +++ b/src/Appwrite/Platform/Modules/Sites/Http/Sites/Create.php @@ -2,7 +2,6 @@ namespace Appwrite\Platform\Modules\Sites\Http\Sites; -use Appwrite\Event\Build; use Appwrite\Event\Event; use Appwrite\Extend\Exception; use Appwrite\Messaging\Adapter\Realtime; @@ -24,13 +23,11 @@ use Utopia\Database\Helpers\Role; use Utopia\Database\Validator\Authorization; use Utopia\Platform\Action; use Utopia\Platform\Scope\HTTP; -use Utopia\Swoole\Request; use Utopia\System\System; use Utopia\Validator\Boolean; use Utopia\Validator\Range; use Utopia\Validator\Text; use Utopia\Validator\WhiteList; -use Utopia\VCS\Adapter\Git\GitHub; class Create extends Base { @@ -83,29 +80,21 @@ class Create extends Base ->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the site.', true) ->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the site? In silent mode, comments will not be made on commits and pull requests.', true) ->param('providerRootDirectory', '', new Text(128, 0), 'Path to site code in the linked repo.', true) - ->param('templateRepository', '', new Text(128, 0), 'Repository name of the template.', true) - ->param('templateOwner', '', new Text(128, 0), 'The name of the owner of the template.', true) - ->param('templateRootDirectory', '', new Text(128, 0), 'Path to site code in the template repo.', true) - ->param('templateVersion', '', new Text(128, 0), 'Version (tag) for the repo linked to the site template.', true) ->param('specification', APP_COMPUTE_SPECIFICATION_DEFAULT, fn (array $plan) => new FrameworkSpecification( $plan, Config::getParam('framework-specifications', []), App::getEnv('_APP_COMPUTE_CPUS', APP_COMPUTE_CPUS_DEFAULT), App::getEnv('_APP_COMPUTE_MEMORY', APP_COMPUTE_MEMORY_DEFAULT) ), 'Framework specification for the site and builds.', true, ['plan']) - ->inject('request') ->inject('response') ->inject('dbForProject') ->inject('project') - ->inject('user') ->inject('queueForEvents') - ->inject('queueForBuilds') ->inject('dbForPlatform') - ->inject('gitHub') ->callback([$this, 'action']); } - public function action(string $siteId, string $name, string $framework, bool $enabled, int $timeout, string $installCommand, string $buildCommand, string $outputDirectory, string $subdomain, string $buildRuntime, string $adapter, string $installationId, ?string $fallbackFile, string $providerRepositoryId, string $providerBranch, bool $providerSilentMode, string $providerRootDirectory, string $templateRepository, string $templateOwner, string $templateRootDirectory, string $templateVersion, string $specification, Request $request, Response $response, Database $dbForProject, Document $project, Document $user, 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 $subdomain, 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] ?? []; @@ -139,20 +128,6 @@ class Create extends Base throw new Exception(Exception::SITE_FRAMEWORK_UNSUPPORTED, 'Framework "' . $framework . '" is not supported'); } - // build from template - $template = new Document([]); - if ( - !empty($templateRepository) - && !empty($templateOwner) - && !empty($templateRootDirectory) - && !empty($templateVersion) - ) { - $template->setAttribute('repositoryName', $templateRepository) - ->setAttribute('ownerName', $templateOwner) - ->setAttribute('rootDirectory', $templateRootDirectory) - ->setAttribute('version', $templateVersion); - } - $installation = $dbForPlatform->getDocument('installations', $installationId); if (!empty($installationId) && $installation->isEmpty()) { @@ -220,57 +195,6 @@ class Create extends Base $site = $dbForProject->updateDocument('sites', $site->getId(), $site); - if (!empty($providerRepositoryId)) { - // Deploy VCS - $this->redeployVcsSite($request, $site, $project, $installation, $dbForProject, $dbForPlatform, $queueForBuilds, $template, $github); - } elseif (!$template->isEmpty()) { - // Deploy non-VCS from template - $deploymentId = ID::unique(); - $deployment = $dbForProject->createDocument('deployments', new Document([ - '$id' => $deploymentId, - '$permissions' => [ - Permission::read(Role::any()), - Permission::update(Role::any()), - Permission::delete(Role::any()), - ], - 'resourceId' => $site->getId(), - 'resourceInternalId' => $site->getInternalId(), - 'resourceType' => 'sites', - 'installCommand' => $site->getAttribute('installCommand', ''), - 'buildCommand' => $site->getAttribute('buildCommand', ''), - 'outputDirectory' => $site->getAttribute('outputDirectory', ''), - 'type' => 'manual', - 'search' => implode(' ', [$deploymentId]), - 'activate' => true, - ])); - - // Preview deployments url - $projectId = $project->getId(); - - $sitesDomain = System::getEnv('_APP_DOMAIN_SITES', ''); - $previewDomain = "{$deploymentId}-{$projectId}.{$sitesDomain}"; - - $rule = Authorization::skip( - fn () => $dbForPlatform->createDocument('rules', new Document([ - '$id' => \md5($previewDomain), - 'projectId' => $project->getId(), - 'projectInternalId' => $project->getInternalId(), - 'domain' => $previewDomain, - 'resourceType' => 'deployment', - 'resourceId' => $deploymentId, - 'resourceInternalId' => $deployment->getInternalId(), - 'status' => 'verified', - 'certificateId' => '', - ])) - ); - - $queueForBuilds - ->setType(BUILD_TYPE_DEPLOYMENT) - ->setResource($site) - ->setDeployment($deployment) - ->setTemplate($template); - } - if (!empty($sitesDomain)) { $rule = Authorization::skip( fn () => $dbForPlatform->createDocument('rules', new Document([ diff --git a/src/Appwrite/Platform/Modules/Sites/Services/Http.php b/src/Appwrite/Platform/Modules/Sites/Services/Http.php index 619702e761..b43919acb7 100644 --- a/src/Appwrite/Platform/Modules/Sites/Services/Http.php +++ b/src/Appwrite/Platform/Modules/Sites/Services/Http.php @@ -9,6 +9,7 @@ use Appwrite\Platform\Modules\Sites\Http\Deployments\Create as CreateDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Delete as DeleteDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Download\Get as DownloadDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Get as GetDeployment; +use Appwrite\Platform\Modules\Sites\Http\Deployments\Template\Create as CreateTemplateDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\Update as UpdateDeployment; use Appwrite\Platform\Modules\Sites\Http\Deployments\XList as ListDeployments; use Appwrite\Platform\Modules\Sites\Http\Frameworks\XList as ListFrameworks; @@ -49,6 +50,7 @@ class Http extends Service // Deployments $this->addAction(CreateDeployment::getName(), new CreateDeployment()); + $this->addAction(CreateTemplateDeployment::getName(), new CreateTemplateDeployment()); $this->addAction(GetDeployment::getName(), new GetDeployment()); $this->addAction(ListDeployments::getName(), new ListDeployments()); $this->addAction(UpdateDeployment::getName(), new UpdateDeployment()); diff --git a/tests/e2e/Services/Functions/FunctionsBase.php b/tests/e2e/Services/Functions/FunctionsBase.php index 0986208bef..e99aedc93e 100644 --- a/tests/e2e/Services/Functions/FunctionsBase.php +++ b/tests/e2e/Services/Functions/FunctionsBase.php @@ -206,6 +206,16 @@ trait FunctionsBase return $deployment; } + protected function createTemplateDeployment(string $functionId, mixed $params = []): mixed + { + $deployment = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/deployments/template', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $params); + + return $deployment; + } + protected function getFunctionUsage(string $functionId, mixed $params): mixed { $usage = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/usage', array_merge([ diff --git a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php index 98e03af1b8..8975a1a5dc 100644 --- a/tests/e2e/Services/Functions/FunctionsCustomServerTest.php +++ b/tests/e2e/Services/Functions/FunctionsCustomServerTest.php @@ -358,6 +358,21 @@ class FunctionsCustomServerTest extends Scope $functionId = $function['body']['$id'] ?? ''; + $deployment = $this->createTemplateDeployment( + $functionId, + [ + 'functionId' => ID::unique(), + 'activate' => true, + 'repository' => $starterTemplate['body']['providerRepositoryId'], + 'owner' => $starterTemplate['body']['providerOwner'], + 'rootDirectory' => $phpRuntime['providerRootDirectory'], + 'version' => $starterTemplate['body']['providerVersion'], + ] + ); + + $this->assertEquals(202, $deployment['headers']['status-code']); + $this->assertNotEmpty($deployment['body']['$id']); + $deployments = $this->listDeployments($functionId); $this->assertEquals(200, $deployments['headers']['status-code']); diff --git a/tests/e2e/Services/Sites/SitesBase.php b/tests/e2e/Services/Sites/SitesBase.php index 8cd36350b6..bc7b6d2722 100644 --- a/tests/e2e/Services/Sites/SitesBase.php +++ b/tests/e2e/Services/Sites/SitesBase.php @@ -228,6 +228,16 @@ trait SitesBase return $deployment; } + protected function createTemplateDeployment(string $siteId, mixed $params = []): mixed + { + $deployment = $this->client->call(Client::METHOD_POST, '/sites/' . $siteId . '/deployments/template', array_merge([ + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + ], $this->getHeaders()), $params); + + return $deployment; + } + protected function getSiteUsage(string $siteId, mixed $params): mixed { $usage = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId . '/usage', array_merge([ diff --git a/tests/e2e/Services/Sites/SitesCustomServerTest.php b/tests/e2e/Services/Sites/SitesCustomServerTest.php index 2a0b11f16c..b01d31ada7 100644 --- a/tests/e2e/Services/Sites/SitesCustomServerTest.php +++ b/tests/e2e/Services/Sites/SitesCustomServerTest.php @@ -566,11 +566,6 @@ class SitesCustomServerTest extends Scope 'installCommand' => $nextjsFramework['installCommand'], 'outputDirectory' => $nextjsFramework['outputDirectory'], 'providerRootDirectory' => $nextjsFramework['providerRootDirectory'], - 'templateOwner' => $starterTemplate['body']['providerOwner'], - 'templateRepository' => $starterTemplate['body']['providerRepositoryId'], - 'templateRootDirectory' => $nextjsFramework['providerRootDirectory'], - 'templateVersion' => $starterTemplate['body']['providerVersion'], - 'providerBranch' => 'main', ] ); @@ -579,6 +574,20 @@ class SitesCustomServerTest extends Scope $siteId = $site['body']['$id'] ?? ''; + $deployment = $this->createTemplateDeployment( + $siteId, + [ + 'owner' => $starterTemplate['body']['providerOwner'], + 'repository' => $starterTemplate['body']['providerRepositoryId'], + 'rootDirectory' => $nextjsFramework['providerRootDirectory'], + 'version' => $starterTemplate['body']['providerVersion'], + 'activate' => true, + ] + ); + + $this->assertEquals(202, $deployment['headers']['status-code']); + $this->assertNotEmpty($deployment['body']['$id']); + $deployments = $this->listDeployments($siteId); $this->assertEquals(200, $deployments['headers']['status-code']); @@ -1214,12 +1223,21 @@ class SitesCustomServerTest extends Scope 'buildCommand' => $template['frameworks'][0]['buildCommand'], 'installCommand' => $template['frameworks'][0]['installCommand'], 'fallbackFile' => $template['frameworks'][0]['fallbackFile'], - 'templateRepository' => $template['providerRepositoryId'], - 'templateOwner' => $template['providerOwner'], - 'templateRootDirectory' => $template['frameworks'][0]['providerRootDirectory'], - 'templateVersion' => $template['providerVersion'], ]); + $this->assertNotEmpty($siteId); + + $deployment = $this->createTemplateDeployment($siteId, [ + 'repository' => $template['providerRepositoryId'], + 'owner' => $template['providerOwner'], + 'rootDirectory' => $template['frameworks'][0]['providerRootDirectory'], + 'version' => $template['providerVersion'], + 'activate' => true + ]); + + $this->assertEquals(202, $deployment['headers']['status-code']); + $this->assertNotEmpty($deployment['body']['$id']); + $this->assertEventually(function () use ($siteId) { $site = $this->getSite($siteId); $this->assertNotEmpty($site['body']['deploymentId']);