Implement ZIP site deployment

This commit is contained in:
Matej Bačo
2025-02-08 21:22:36 +01:00
parent f8b27c0b76
commit 622ae009bd
6 changed files with 114 additions and 15 deletions
+3
View File
@@ -30,6 +30,9 @@ RUN \
RUN apk add libwebp
# TODO: Move to appwrite/docker-base
RUN apk add zip
WORKDIR /usr/src/code
COPY --from=composer /usr/local/src/vendor /usr/src/code/vendor
@@ -261,8 +261,16 @@ class Builds extends Action
Console::execute('rm -rf ' . \escapeshellarg($tmpTemplateDirectory), '', $stdout, $stderr);
$directorySize = $deviceForFunctions->getFileSize($source);
$build = $dbForProject->updateDocument('builds', $build->getId(), $build->setAttribute('source', $source));
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment->setAttribute('path', $source)->setAttribute('size', $directorySize));
$build = $build->setAttribute('source', $source);
$deployment = $deployment
->setAttribute('path', $source)
->setAttribute('size', $directorySize)
->setAttribute('metadata', ['content_type' => 'application/gzip']);
$build = $dbForProject->updateDocument('builds', $build->getId(), $build);
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
}
} elseif ($isNewBuild && $isVcsEnabled) {
// VCS and VCS+Temaplte
@@ -417,10 +425,16 @@ class Builds extends Action
Console::execute('rm -rf ' . \escapeshellarg($tmpPath), '', $stdout, $stderr);
$build = $dbForProject->updateDocument('builds', $build->getId(), $build->setAttribute('source', $source));
$directorySize = $deviceForFunctions->getFileSize($source);
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment->setAttribute('path', $source)->setAttribute('size', $directorySize));
$build = $build->setAttribute('source', $source);
$deployment = $build
->setAttribute('path', $source)
->setAttribute('size', $directorySize)
->setAttribute('metadata', ['content_type' => 'application/gzip']);
$build = $dbForProject->updateDocument('builds', $build->getId(), $build);
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment);
$this->runGitAction('processing', $github, $providerCommitHash, $owner, $repositoryName, $project, $resource, $deployment->getId(), $dbForProject, $dbForPlatform);
}
@@ -565,7 +579,22 @@ class Builds extends Action
Co::join([
Co\go(function () use ($executor, &$response, $project, $deployment, $source, $resource, $runtime, $vars, $command, $cpus, $memory, $timeout, &$err, $version) {
try {
$command = $version === 'v2' ? 'tar -zxf /tmp/code.tar.gz -C /usr/code && cd /usr/local/src/ && ./build.sh' : 'tar -zxf /tmp/code.tar.gz -C /mnt/code && helpers/build.sh "' . \trim(\escapeshellarg($command), "\'") . '"';
$contentType = $deployment->getAttribute('metadata', [])['content_type'] ?? '';
$extractCommand = '';
switch ($contentType) {
case 'application/zip':
$extractCommand = 'unzip /tmp/code.tar.gz -d /mnt/code';
break;
case 'application/gzip':
$extractCommand = 'tar -zxf /tmp/code.tar.gz -C /mnt/code';
break;
default:
throw new \Exception('Unsupported deployment content type: ' . $contentType);
break;
}
$command = $version === 'v2' ? 'tar -zxf /tmp/code.tar.gz -C /usr/code && cd /usr/local/src/ && ./build.sh' : ($extractCommand . ' && helpers/build.sh "' . \trim(\escapeshellarg($command), "\'") . '"');
// TODO: Detect adapter if adapter is empty
$response = $executor->createRuntime(
@@ -119,7 +119,7 @@ class Create extends Action
throw new Exception(Exception::STORAGE_FILE_EMPTY, 'No file sent');
}
$fileExt = new FileExt([FileExt::TYPE_GZIP]);
$fileExt = new FileExt([FileExt::TYPE_GZIP, 'zip']); // TODO: Move 'zip' to Storage library
$fileSizeValidator = new FileSize(System::getEnv('_APP_COMPUTE_SIZE_LIMIT', '30000000'));
$upload = new Upload();
@@ -172,7 +172,9 @@ class Create extends Action
$deployment = $dbForProject->getDocument('deployments', $deploymentId);
$metadata = ['content_type' => $deviceForLocal->getFileMimeType($fileTmpName)];
\var_dump($metadata);
if (!$deployment->isEmpty()) {
\var_dump("Setting");
$chunks = $deployment->getAttribute('chunksTotal', 1);
$metadata = $deployment->getAttribute('metadata', []);
if ($chunk === -1) {
@@ -206,6 +208,7 @@ class Create extends Action
$fileSize = $deviceForFunctions->getFileSize($path);
if ($deployment->isEmpty()) {
\var_dump("Creating");
$deployment = $dbForProject->createDocument('deployments', new Document([
'$id' => $deploymentId,
'$permissions' => [
@@ -249,6 +252,7 @@ class Create extends Action
]))
);
} else {
\var_dump("updating");
$deployment = $dbForProject->updateDocument('deployments', $deploymentId, $deployment->setAttribute('size', $fileSize)->setAttribute('metadata', $metadata));
}
@@ -259,6 +263,7 @@ class Create extends Action
->setDeployment($deployment);
} else {
if ($deployment->isEmpty()) {
\var_dump("Creating 2");
$deployment = $dbForProject->createDocument('deployments', new Document([
'$id' => $deploymentId,
'$permissions' => [
+29 -8
View File
@@ -12,9 +12,6 @@ trait SitesBase
{
use Async;
protected string $stdout = '';
protected string $stderr = '';
protected function setupSite(mixed $params): string
{
$site = $this->client->call(Client::METHOD_POST, '/sites', array_merge([
@@ -164,18 +161,42 @@ trait SitesBase
return $logs;
}
protected function packageSite(string $site): CURLFile
protected function packageSite(string $site, string $format = 'gzip'): CURLFile
{
$extension = '';
$command = '';
$header = '';
switch ($format) {
case 'gzip':
$extension = 'tar.gz';
$command = 'tar --exclude code.tar.gz -czf code.tar.gz .';
$header = 'application/x-gzip';
break;
case 'zip':
$extension = 'zip';
$command = 'zip -x code.zip -r code.zip .';
$header = 'application/zip';
break;
default:
throw new \Exception('Invalid package format');
}
$folderPath = realpath(__DIR__ . '/../../../resources/sites') . "/$site";
$tarPath = "$folderPath/code.tar.gz";
$filePath = "$folderPath/code." . $extension;
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
$stdout = '';
$stderr = '';
$exitCode = Console::execute("cd $folderPath && " . $command, '', $stdout, $stderr);
if (filesize($tarPath) > 1024 * 1024 * 5) {
$this->assertEquals(0, $exitCode);
$this->assertEmpty($stderr);
if (filesize($filePath) > 1024 * 1024 * 5) {
throw new \Exception('Code package is too large. Use the chunked upload method instead.');
}
return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
return new CURLFile($filePath, $header, \basename($filePath));
}
protected function createDeployment(string $siteId, mixed $params = []): mixed
@@ -1088,5 +1088,46 @@ class SitesCustomServerTest extends Scope
$this->cleanupSite($site['body']['$id']);
}
public function testSiteZipDeployment(): void
{
$siteId = $this->setupSite([
'siteId' => ID::unique(),
'name' => 'A site',
'framework' => 'other',
'adapter' => 'static',
'buildRuntime' => 'static-1',
'outputDirectory' => './',
'buildCommand' => '',
'installCommand' => '',
'fallbackFile' => '',
]);
$this->assertNotEmpty($siteId);
$deploymentId = $this->setupDeployment($siteId, [
'code' => $this->packageSite('static', 'zip'),
'activate' => 'true'
]);
$this->assertNotEmpty($deploymentId);
$domain = $this->getSiteDomain($siteId);
$this->assertNotEmpty($domain);
$proxyClient = new Client();
$proxyClient->setEndpoint('http://' . $domain);
$response = $proxyClient->call(Client::METHOD_GET, '/', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
]));
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString("Hello Appwrite", $response['body']);
$this->cleanupSite($siteId);
}
// TODO: Add tests for deletion of resources when site is deleted
}
Binary file not shown.