mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
feat: add branch deployments to appwrite
This commit is contained in:
@@ -311,19 +311,27 @@ class Builds extends Action
|
||||
$templateRepositoryName = $template->getAttribute('repositoryName', '');
|
||||
$templateOwnerName = $template->getAttribute('ownerName', '');
|
||||
$templateVersion = $template->getAttribute('version', '');
|
||||
$templateBranch = $template->getAttribute('branch', '');
|
||||
|
||||
$templateRootDirectory = $template->getAttribute('rootDirectory', '');
|
||||
$templateRootDirectory = \rtrim($templateRootDirectory, '/');
|
||||
$templateRootDirectory = \ltrim($templateRootDirectory, '.');
|
||||
$templateRootDirectory = \ltrim($templateRootDirectory, '/');
|
||||
|
||||
if (!empty($templateRepositoryName) && !empty($templateOwnerName) && !empty($templateVersion)) {
|
||||
if (!empty($templateRepositoryName) && !empty($templateOwnerName) && (!empty($templateVersion) || !empty($templateBranch))) {
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
|
||||
// Clone template repo
|
||||
$tmpTemplateDirectory = '/tmp/builds/' . $deploymentId . '-template';
|
||||
$gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory);
|
||||
|
||||
if(empty($templateVersion)) {
|
||||
$gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateBranch, GitHub::CLONE_TYPE_BRANCH, $tmpTemplateDirectory, $templateRootDirectory);
|
||||
} else {
|
||||
// True template
|
||||
$gitCloneCommandForTemplate = $github->generateCloneCommand($templateOwnerName, $templateRepositoryName, $templateVersion, GitHub::CLONE_TYPE_TAG, $tmpTemplateDirectory, $templateRootDirectory);
|
||||
}
|
||||
|
||||
$exit = Console::execute($gitCloneCommandForTemplate, '', $stdout, $stderr);
|
||||
|
||||
if ($exit !== 0) {
|
||||
|
||||
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Sites\Http\Deployments\Direct;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Authorization;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\Swoole\Request;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\Boolean;
|
||||
use Utopia\Validator\Text;
|
||||
use Utopia\VCS\Adapter\Git\GitHub;
|
||||
|
||||
class Create extends Base
|
||||
{
|
||||
use HTTP;
|
||||
|
||||
public static function getName()
|
||||
{
|
||||
return 'createDirectDeployment';
|
||||
}
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->setHttpMethod(Action::HTTP_REQUEST_METHOD_POST)
|
||||
->setHttpPath('/v1/sites/direct')
|
||||
->desc('Create direct deployment')
|
||||
->groups(['api', 'sites'])
|
||||
->label('scope', 'sites.write')
|
||||
->label('resourceType', RESOURCE_TYPE_SITES)
|
||||
->label('event', 'sites.[siteId].deployments.[deploymentId].create')
|
||||
->label('audits.event', 'deployment.create')
|
||||
->label('audits.resource', 'site/{request.siteId}')
|
||||
->label('sdk', new Method(
|
||||
namespace: 'sites',
|
||||
group: 'deployments',
|
||||
name: 'createDirectDeployment',
|
||||
description: <<<EOT
|
||||
Create a deployment directly from a repository branch.
|
||||
EOT,
|
||||
auth: [AuthType::KEY],
|
||||
responses: [
|
||||
new SDKResponse(
|
||||
code: Response::STATUS_CODE_ACCEPTED,
|
||||
model: Response::MODEL_DEPLOYMENT,
|
||||
)
|
||||
],
|
||||
))
|
||||
->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('branch', '', new Text(128, 0), 'Branch to create deployment from.')
|
||||
->param('activate', true, 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 $branch,
|
||||
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,
|
||||
'branch' => $branch
|
||||
]);
|
||||
|
||||
|
||||
if (!empty($site->getAttribute('providerRepositoryId'))) {
|
||||
$installation = $dbForPlatform->getDocument('installations', $site->getAttribute('installationId'));
|
||||
|
||||
$deployment = $this->redeployVcsSite(
|
||||
request: $request,
|
||||
site: $site,
|
||||
project: $project,
|
||||
installation: $installation,
|
||||
dbForProject: $dbForProject,
|
||||
dbForPlatform: $dbForPlatform,
|
||||
queueForBuilds: $queueForBuilds,
|
||||
template: $template,
|
||||
github: $github,
|
||||
activate: $activate,
|
||||
);
|
||||
|
||||
$queueForEvents
|
||||
->setParam('siteId', $site->getId())
|
||||
->setParam('deploymentId', $deployment->getId());
|
||||
|
||||
$response
|
||||
->setStatusCode(Response::STATUS_CODE_ACCEPTED)
|
||||
->dynamic($deployment, Response::MODEL_DEPLOYMENT);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$branchUrl = "https://github.com/$owner/$repository/tree/$branch";
|
||||
$repositoryUrl = "https://github.com/$owner/$repository";
|
||||
|
||||
try {
|
||||
$commitDetails = $github->getLatestCommit($owner, $repository, $branch);
|
||||
} catch (\Throwable $error) {
|
||||
// Ignore; deployment can continue
|
||||
}
|
||||
|
||||
$commands = [];
|
||||
if (!empty($site->getAttribute('installCommand', ''))) {
|
||||
$commands[] = $site->getAttribute('installCommand', '');
|
||||
}
|
||||
if (!empty($site->getAttribute('buildCommand', ''))) {
|
||||
$commands[] = $site->getAttribute('buildCommand', '');
|
||||
}
|
||||
|
||||
$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->getSequence(),
|
||||
'resourceType' => 'sites',
|
||||
'buildCommands' => \implode(' && ', $commands),
|
||||
'buildOutput' => $site->getAttribute('outputDirectory', ''),
|
||||
'adapter' => $site->getAttribute('adapter', ''),
|
||||
'fallbackFile' => $site->getAttribute('fallbackFile', ''),
|
||||
'providerRepositoryName' => $repository,
|
||||
'providerRepositoryOwner' => $owner,
|
||||
'providerRepositoryUrl' => $repositoryUrl,
|
||||
'providerBranchUrl' => $branchUrl,
|
||||
'providerBranch' => $branch,
|
||||
'providerCommitHash' => $commitDetails['commitHash'] ?? '',
|
||||
'providerCommitAuthorUrl' => $commitDetails['commitAuthorUrl'] ?? '',
|
||||
'providerCommitAuthor' => $commitDetails['commitAuthor'] ?? '',
|
||||
'providerCommitMessage' => mb_strimwidth($commitDetails['commitMessage'] ?? '', 0, 255, '...'),
|
||||
'providerCommitUrl' => $commitDetails['commitUrl'] ?? '',
|
||||
'type' => 'vcs',
|
||||
'activate' => $activate,
|
||||
]));
|
||||
|
||||
$site = $site
|
||||
->setAttribute('latestDeploymentId', $deployment->getId())
|
||||
->setAttribute('latestDeploymentInternalId', $deployment->getSequence())
|
||||
->setAttribute('latestDeploymentCreatedAt', $deployment->getCreatedAt())
|
||||
->setAttribute('latestDeploymentStatus', $deployment->getAttribute('status', ''));
|
||||
$dbForProject->updateDocument('sites', $site->getId(), $site);
|
||||
|
||||
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
||||
$domain = ID::unique() . "." . $sitesDomain;
|
||||
|
||||
// TODO: @christyjacob remove once we migrate the rules in 1.7.x
|
||||
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique();
|
||||
|
||||
Authorization::skip(
|
||||
fn () => $dbForPlatform->createDocument('rules', new Document([
|
||||
'$id' => $ruleId,
|
||||
'projectId' => $project->getId(),
|
||||
'projectInternalId' => $project->getSequence(),
|
||||
'domain' => $domain,
|
||||
'type' => 'deployment',
|
||||
'trigger' => 'deployment',
|
||||
'deploymentId' => $deployment->isEmpty() ? '' : $deployment->getId(),
|
||||
'deploymentInternalId' => $deployment->isEmpty() ? '' : $deployment->getSequence(),
|
||||
'deploymentResourceType' => 'site',
|
||||
'deploymentResourceId' => $site->getId(),
|
||||
'deploymentResourceInternalId' => $site->getSequence(),
|
||||
'status' => 'verified',
|
||||
'certificateId' => '',
|
||||
'owner' => 'Appwrite',
|
||||
'region' => $project->getAttribute('region')
|
||||
]))
|
||||
);
|
||||
|
||||
$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);
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,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\Duplicate\Create as CreateDuplicateDeployment;
|
||||
use Appwrite\Platform\Modules\Sites\Http\Deployments\Direct\Create as CreateDirectDeployment;
|
||||
use Appwrite\Platform\Modules\Sites\Http\Deployments\Get as GetDeployment;
|
||||
use Appwrite\Platform\Modules\Sites\Http\Deployments\Status\Update as UpdateDeploymentStatus;
|
||||
use Appwrite\Platform\Modules\Sites\Http\Deployments\Template\Create as CreateTemplateDeployment;
|
||||
@@ -60,6 +61,7 @@ class Http extends Service
|
||||
$this->addAction(DownloadDeployment::getName(), new DownloadDeployment());
|
||||
$this->addAction(CreateDuplicateDeployment::getName(), new CreateDuplicateDeployment());
|
||||
$this->addAction(UpdateDeploymentStatus::getName(), new UpdateDeploymentStatus());
|
||||
$this->addAction(CreateDirectDeployment::getName(), new CreateDirectDeployment());
|
||||
|
||||
// Logs
|
||||
$this->addAction(GetLog::getName(), new GetLog());
|
||||
|
||||
Reference in New Issue
Block a user