2024-10-22 11:00:10 +00:00
|
|
|
<?php
|
|
|
|
|
|
2024-10-22 15:01:38 +00:00
|
|
|
namespace Appwrite\Platform\Modules\Compute;
|
2024-10-22 11:00:10 +00:00
|
|
|
|
|
|
|
|
use Appwrite\Event\Build;
|
|
|
|
|
use Appwrite\Extend\Exception;
|
2025-03-05 09:48:26 +00:00
|
|
|
use Appwrite\Query;
|
2024-10-22 11:00:10 +00:00
|
|
|
use Utopia\CLI\Console;
|
|
|
|
|
use Utopia\Database\Database;
|
|
|
|
|
use Utopia\Database\Document;
|
|
|
|
|
use Utopia\Database\Helpers\ID;
|
|
|
|
|
use Utopia\Database\Helpers\Permission;
|
|
|
|
|
use Utopia\Database\Helpers\Role;
|
2024-11-18 14:57:07 +00:00
|
|
|
use Utopia\Database\Validator\Authorization;
|
2024-10-22 15:01:38 +00:00
|
|
|
use Utopia\Platform\Action;
|
2024-10-22 11:00:10 +00:00
|
|
|
use Utopia\Swoole\Request;
|
|
|
|
|
use Utopia\System\System;
|
|
|
|
|
use Utopia\VCS\Adapter\Git\GitHub;
|
|
|
|
|
use Utopia\VCS\Exception\RepositoryNotFound;
|
|
|
|
|
|
2024-10-22 15:01:38 +00:00
|
|
|
class Base extends Action
|
2024-10-22 11:00:10 +00:00
|
|
|
{
|
2025-02-19 12:39:11 +00:00
|
|
|
public function redeployVcsFunction(Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, string $referenceType = 'branch', string $reference = ''): Document
|
2024-10-22 11:00:10 +00:00
|
|
|
{
|
|
|
|
|
$deploymentId = ID::unique();
|
|
|
|
|
$entrypoint = $function->getAttribute('entrypoint', '');
|
|
|
|
|
$providerInstallationId = $installation->getAttribute('providerInstallationId', '');
|
|
|
|
|
$privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY');
|
|
|
|
|
$githubAppId = System::getEnv('_APP_VCS_GITHUB_APP_ID');
|
|
|
|
|
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
|
|
|
|
|
$owner = $github->getOwnerName($providerInstallationId);
|
|
|
|
|
$providerRepositoryId = $function->getAttribute('providerRepositoryId', '');
|
|
|
|
|
try {
|
|
|
|
|
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
|
|
|
|
|
if (empty($repositoryName)) {
|
|
|
|
|
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
|
|
|
|
}
|
|
|
|
|
} catch (RepositoryNotFound $e) {
|
|
|
|
|
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
|
|
|
|
}
|
2025-02-19 10:50:25 +00:00
|
|
|
|
|
|
|
|
// TODO: Support tag and commit in future
|
|
|
|
|
if ($referenceType === 'branch') {
|
|
|
|
|
$providerBranch = empty($reference) ? $function->getAttribute('providerBranch', 'main') : $reference;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-22 11:00:10 +00:00
|
|
|
$authorUrl = "https://github.com/$owner";
|
|
|
|
|
$repositoryUrl = "https://github.com/$owner/$repositoryName";
|
|
|
|
|
$branchUrl = "https://github.com/$owner/$repositoryName/tree/$providerBranch";
|
|
|
|
|
|
|
|
|
|
$commitDetails = [];
|
|
|
|
|
if ($template->isEmpty()) {
|
|
|
|
|
try {
|
|
|
|
|
$commitDetails = $github->getLatestCommit($owner, $repositoryName, $providerBranch);
|
|
|
|
|
} catch (\Throwable $error) {
|
|
|
|
|
Console::warning('Failed to get latest commit details');
|
|
|
|
|
Console::warning($error->getMessage());
|
|
|
|
|
Console::warning($error->getTraceAsString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$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' => $entrypoint,
|
|
|
|
|
'commands' => $function->getAttribute('commands', ''),
|
|
|
|
|
'type' => 'vcs',
|
|
|
|
|
'installationId' => $installation->getId(),
|
|
|
|
|
'installationInternalId' => $installation->getInternalId(),
|
|
|
|
|
'providerRepositoryId' => $providerRepositoryId,
|
|
|
|
|
'repositoryId' => $function->getAttribute('repositoryId', ''),
|
|
|
|
|
'repositoryInternalId' => $function->getAttribute('repositoryInternalId', ''),
|
|
|
|
|
'providerBranchUrl' => $branchUrl,
|
|
|
|
|
'providerRepositoryName' => $repositoryName,
|
|
|
|
|
'providerRepositoryOwner' => $owner,
|
|
|
|
|
'providerRepositoryUrl' => $repositoryUrl,
|
|
|
|
|
'providerCommitHash' => $commitDetails['commitHash'] ?? '',
|
|
|
|
|
'providerCommitAuthorUrl' => $authorUrl,
|
|
|
|
|
'providerCommitAuthor' => $commitDetails['commitAuthor'] ?? '',
|
|
|
|
|
'providerCommitMessage' => $commitDetails['commitMessage'] ?? '',
|
|
|
|
|
'providerCommitUrl' => $commitDetails['commitUrl'] ?? '',
|
|
|
|
|
'providerBranch' => $providerBranch,
|
|
|
|
|
'providerRootDirectory' => $function->getAttribute('providerRootDirectory', ''),
|
|
|
|
|
'search' => implode(' ', [$deploymentId, $entrypoint]),
|
2025-02-19 12:39:11 +00:00
|
|
|
'activate' => $activate,
|
2024-10-22 11:00:10 +00:00
|
|
|
]));
|
|
|
|
|
|
|
|
|
|
$queueForBuilds
|
|
|
|
|
->setType(BUILD_TYPE_DEPLOYMENT)
|
|
|
|
|
->setResource($function)
|
|
|
|
|
->setDeployment($deployment)
|
|
|
|
|
->setTemplate($template);
|
2025-02-14 23:36:46 +00:00
|
|
|
|
|
|
|
|
return $deployment;
|
2024-10-22 11:00:10 +00:00
|
|
|
}
|
2024-10-22 15:01:38 +00:00
|
|
|
|
2025-02-19 12:39:11 +00:00
|
|
|
public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, string $referenceType = 'branch', string $reference = ''): Document
|
2024-10-22 15:01:38 +00:00
|
|
|
{
|
|
|
|
|
$deploymentId = ID::unique();
|
|
|
|
|
$providerInstallationId = $installation->getAttribute('providerInstallationId', '');
|
|
|
|
|
$privateKey = System::getEnv('_APP_VCS_GITHUB_PRIVATE_KEY');
|
|
|
|
|
$githubAppId = System::getEnv('_APP_VCS_GITHUB_APP_ID');
|
|
|
|
|
$github->initializeVariables($providerInstallationId, $privateKey, $githubAppId);
|
|
|
|
|
$owner = $github->getOwnerName($providerInstallationId);
|
|
|
|
|
$providerRepositoryId = $site->getAttribute('providerRepositoryId', '');
|
|
|
|
|
try {
|
|
|
|
|
$repositoryName = $github->getRepositoryName($providerRepositoryId) ?? '';
|
|
|
|
|
if (empty($repositoryName)) {
|
|
|
|
|
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
|
|
|
|
}
|
|
|
|
|
} catch (RepositoryNotFound $e) {
|
|
|
|
|
throw new Exception(Exception::PROVIDER_REPOSITORY_NOT_FOUND);
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-19 10:50:25 +00:00
|
|
|
// TODO: Support tag and commit in future
|
|
|
|
|
if ($referenceType === 'branch') {
|
|
|
|
|
$providerBranch = empty($reference) ? $site->getAttribute('providerBranch', 'main') : $reference;
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-22 15:01:38 +00:00
|
|
|
$authorUrl = "https://github.com/$owner";
|
|
|
|
|
$repositoryUrl = "https://github.com/$owner/$repositoryName";
|
|
|
|
|
$branchUrl = "https://github.com/$owner/$repositoryName/tree/$providerBranch";
|
|
|
|
|
|
|
|
|
|
$commitDetails = [];
|
|
|
|
|
if ($template->isEmpty()) {
|
|
|
|
|
try {
|
|
|
|
|
$commitDetails = $github->getLatestCommit($owner, $repositoryName, $providerBranch);
|
|
|
|
|
} catch (\Throwable $error) {
|
|
|
|
|
Console::warning('Failed to get latest commit details');
|
|
|
|
|
Console::warning($error->getMessage());
|
|
|
|
|
Console::warning($error->getTraceAsString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$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',
|
|
|
|
|
'buildCommand' => $site->getAttribute('buildCommand', ''),
|
|
|
|
|
'installCommand' => $site->getAttribute('installCommand', ''),
|
|
|
|
|
'outputDirectory' => $site->getAttribute('outputDirectory', ''),
|
|
|
|
|
'type' => 'vcs',
|
|
|
|
|
'installationId' => $installation->getId(),
|
|
|
|
|
'installationInternalId' => $installation->getInternalId(),
|
|
|
|
|
'providerRepositoryId' => $providerRepositoryId,
|
|
|
|
|
'repositoryId' => $site->getAttribute('repositoryId', ''),
|
|
|
|
|
'repositoryInternalId' => $site->getAttribute('repositoryInternalId', ''),
|
|
|
|
|
'providerBranchUrl' => $branchUrl,
|
|
|
|
|
'providerRepositoryName' => $repositoryName,
|
|
|
|
|
'providerRepositoryOwner' => $owner,
|
|
|
|
|
'providerRepositoryUrl' => $repositoryUrl,
|
|
|
|
|
'providerCommitHash' => $commitDetails['commitHash'] ?? '',
|
|
|
|
|
'providerCommitAuthorUrl' => $authorUrl,
|
|
|
|
|
'providerCommitAuthor' => $commitDetails['commitAuthor'] ?? '',
|
|
|
|
|
'providerCommitMessage' => $commitDetails['commitMessage'] ?? '',
|
|
|
|
|
'providerCommitUrl' => $commitDetails['commitUrl'] ?? '',
|
|
|
|
|
'providerBranch' => $providerBranch,
|
|
|
|
|
'providerRootDirectory' => $site->getAttribute('providerRootDirectory', ''),
|
|
|
|
|
'search' => implode(' ', [$deploymentId]),
|
2025-02-19 12:39:11 +00:00
|
|
|
'activate' => $activate,
|
2024-10-22 15:01:38 +00:00
|
|
|
]));
|
|
|
|
|
|
2024-11-18 14:57:07 +00:00
|
|
|
$sitesDomain = System::getEnv('_APP_DOMAIN_SITES', '');
|
2025-02-20 13:22:30 +00:00
|
|
|
$domain = ID::unique() . "." . $sitesDomain;
|
2025-03-07 09:43:54 +00:00
|
|
|
|
|
|
|
|
// TODO: @christyjacob remove once we migrate the rules in 1.7.x
|
|
|
|
|
$ruleId = System::getEnv('_APP_RULES_FORMAT') === 'md5' ? md5($domain) : ID::unique();
|
|
|
|
|
|
2025-02-20 13:22:30 +00:00
|
|
|
Authorization::skip(
|
2025-02-04 09:51:33 +00:00
|
|
|
fn () => $dbForPlatform->createDocument('rules', new Document([
|
2024-11-18 14:57:07 +00:00
|
|
|
'$id' => $ruleId,
|
|
|
|
|
'projectId' => $project->getId(),
|
|
|
|
|
'projectInternalId' => $project->getInternalId(),
|
|
|
|
|
'domain' => $domain,
|
2025-02-23 20:34:14 +00:00
|
|
|
'type' => 'deployment',
|
2025-03-07 09:14:45 +00:00
|
|
|
'deploymentId' => $deployment->getId(),
|
|
|
|
|
'deploymentInternalId' => $deployment->getInternalId(),
|
|
|
|
|
'deploymentResourceType' => 'site',
|
|
|
|
|
'deploymentResourceId' => $site->getId(),
|
|
|
|
|
'deploymentResourceInternalId' => $site->getInternalId(),
|
|
|
|
|
'deploymentVcsProviderBranch' => $providerBranch,
|
|
|
|
|
'deploymentUpdatePolicy' => '',
|
2024-11-18 14:57:07 +00:00
|
|
|
'status' => 'verified',
|
|
|
|
|
'certificateId' => '',
|
2025-02-25 09:47:47 +00:00
|
|
|
'search' => implode(' ', [$ruleId, $domain]),
|
2024-11-18 14:57:07 +00:00
|
|
|
]))
|
|
|
|
|
);
|
|
|
|
|
|
2024-10-22 15:01:38 +00:00
|
|
|
$queueForBuilds
|
|
|
|
|
->setType(BUILD_TYPE_DEPLOYMENT)
|
|
|
|
|
->setResource($site)
|
|
|
|
|
->setDeployment($deployment)
|
|
|
|
|
->setTemplate($template);
|
2025-02-14 23:36:46 +00:00
|
|
|
|
|
|
|
|
return $deployment;
|
2024-10-22 15:01:38 +00:00
|
|
|
}
|
2025-03-05 09:48:26 +00:00
|
|
|
|
|
|
|
|
protected function listRules(Document $project, array $queries, Database $database, callable $callback): void
|
|
|
|
|
{
|
|
|
|
|
$limit = 100;
|
|
|
|
|
$cursor = null;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
$queries = \array_merge([
|
|
|
|
|
Query::limit($limit),
|
|
|
|
|
Query::equal("projectInternalId", [$project->getInternalId()])
|
|
|
|
|
], $queries);
|
|
|
|
|
|
|
|
|
|
if ($cursor !== null) {
|
|
|
|
|
$queries[] = Query::cursorAfter($cursor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$results = $database->find('rules', $queries);
|
|
|
|
|
|
|
|
|
|
$total = \count($results);
|
|
|
|
|
if ($total > 0) {
|
|
|
|
|
$cursor = $results[$total - 1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($total < $limit) {
|
|
|
|
|
$cursor = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach ($results as $document) {
|
|
|
|
|
if (is_callable($callback)) {
|
|
|
|
|
$callback($document);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while (!\is_null($cursor));
|
|
|
|
|
}
|
2024-10-22 11:00:10 +00:00
|
|
|
}
|