Skip to content

Commit c996f1d

Browse files
committed
Merge origin/main into feat-backup-policy-migration
Resolve conflicts keeping both backups and sites support.
2 parents 8c8d472 + 35df40d commit c996f1d

19 files changed

Lines changed: 1008 additions & 57 deletions

File tree

composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@
2929
"utopia-php/database": "5.*",
3030
"utopia-php/storage": "0.18.*",
3131
"utopia-php/dsn": "0.2.*",
32-
"utopia-php/console": "0.0.*",
3332
"halaxa/json-machine": "^1.2"
3433
},
3534
"require-dev": {

composer.lock

Lines changed: 0 additions & 48 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Migration/Cache.php

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Utopia\Migration\Resources\Database\Row;
88
use Utopia\Migration\Resources\Database\Table;
99
use Utopia\Migration\Resources\Functions\Deployment;
10+
use Utopia\Migration\Resources\Sites\Deployment as SiteDeployment;
1011
use Utopia\Migration\Resources\Storage\File;
1112

1213
/**
@@ -69,6 +70,11 @@ public function resolveResourceCacheKey(Resource $resource): string
6970
$keys[] = $resource->getFunction()->getSequence();
7071
break;
7172

73+
case Resource::TYPE_SITE_DEPLOYMENT:
74+
/** @var SiteDeployment $resource */
75+
$keys[] = $resource->getSite()->getSequence();
76+
break;
77+
7278
default:
7379
break;
7480
}
@@ -99,8 +105,8 @@ public function add(Resource $resource): void
99105
return;
100106
}
101107

102-
if ($resource->getName() == Resource::TYPE_FILE || $resource->getName() == Resource::TYPE_DEPLOYMENT) {
103-
/** @var File|Deployment $resource */
108+
if ($resource->getName() == Resource::TYPE_FILE || $resource->getName() == Resource::TYPE_DEPLOYMENT || $resource->getName() == Resource::TYPE_SITE_DEPLOYMENT) {
109+
/** @var File|Deployment|SiteDeployment $resource */
104110
$resource->setData(''); // Prevent Memory Leak
105111
}
106112

src/Migration/Destinations/Appwrite.php

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44

55
use Appwrite\AppwriteException;
66
use Appwrite\Client;
7+
use Appwrite\Enums\Adapter;
8+
use Appwrite\Enums\BuildRuntime;
79
use Appwrite\Enums\Compression;
10+
use Appwrite\Enums\Framework;
811
use Appwrite\Enums\PasswordHash;
912
use Appwrite\Enums\Runtime;
1013
use Appwrite\InputFile;
1114
use Appwrite\Services\Functions;
15+
use Appwrite\Services\Sites;
1216
use Appwrite\Services\Storage;
1317
use Appwrite\Services\Teams;
1418
use Appwrite\Services\Users;
@@ -43,6 +47,9 @@
4347
use Utopia\Migration\Resources\Functions\Deployment;
4448
use Utopia\Migration\Resources\Functions\EnvVar;
4549
use Utopia\Migration\Resources\Functions\Func;
50+
use Utopia\Migration\Resources\Sites\Deployment as SiteDeployment;
51+
use Utopia\Migration\Resources\Sites\EnvVar as SiteEnvVar;
52+
use Utopia\Migration\Resources\Sites\Site;
4653
use Utopia\Migration\Resources\Storage\Bucket;
4754
use Utopia\Migration\Resources\Storage\File;
4855
use Utopia\Migration\Transfer;
@@ -55,6 +62,7 @@ class Appwrite extends Destination
5562
protected string $key;
5663

5764
private Functions $functions;
65+
private Sites $sites;
5866
private Storage $storage;
5967
private Teams $teams;
6068
private Users $users;
@@ -88,6 +96,7 @@ public function __construct(
8896
->setKey($key);
8997

9098
$this->functions = new Functions($this->client);
99+
$this->sites = new Sites($this->client);
91100
$this->storage = new Storage($this->client);
92101
$this->teams = new Teams($this->client);
93102
$this->users = new Users($this->client);
@@ -132,6 +141,11 @@ public static function getSupportedResources(): array
132141

133142
// Backups
134143
Resource::TYPE_BACKUP_POLICY,
144+
145+
// Sites
146+
Resource::TYPE_SITE,
147+
Resource::TYPE_SITE_DEPLOYMENT,
148+
Resource::TYPE_SITE_VARIABLE,
135149
];
136150
}
137151

@@ -203,6 +217,15 @@ public function report(array $resources = [], array $resourceIds = []): array
203217
$this->functions->create('', '', Runtime::NODE180());
204218
}
205219

220+
// Sites
221+
if (\in_array(Resource::TYPE_SITE, $resources)) {
222+
$scope = 'sites.read';
223+
$this->sites->list();
224+
225+
$scope = 'sites.write';
226+
$this->sites->create('', '', Framework::OTHER(), BuildRuntime::STATIC1());
227+
}
228+
206229
} catch (AppwriteException $e) {
207230
if ($e->getCode() === 403) {
208231
throw new \Exception('Missing scope: ' . $scope, previous: $e);
@@ -274,6 +297,7 @@ protected function import(array $resources, callable $callback): void
274297
Transfer::GROUP_AUTH => $this->importAuthResource($resource),
275298
Transfer::GROUP_FUNCTIONS => $this->importFunctionResource($resource),
276299
Transfer::GROUP_BACKUPS => $this->importBackupResource($resource),
300+
Transfer::GROUP_SITES => $this->importSiteResource($resource),
277301
default => throw new \Exception('Invalid resource group'),
278302
};
279303
} catch (\Throwable $e) {
@@ -1607,4 +1631,205 @@ private function importDeployment(Deployment $deployment): Resource
16071631

16081632
return $deployment;
16091633
}
1634+
1635+
/**
1636+
* @throws AppwriteException
1637+
*/
1638+
public function importSiteResource(Resource $resource): Resource
1639+
{
1640+
switch ($resource->getName()) {
1641+
case Resource::TYPE_SITE:
1642+
/** @var Site $resource */
1643+
1644+
$buildRuntime = match ($resource->getBuildRuntime()) {
1645+
'node-14.5' => BuildRuntime::NODE145(),
1646+
'node-16.0' => BuildRuntime::NODE160(),
1647+
'node-18.0' => BuildRuntime::NODE180(),
1648+
'node-19.0' => BuildRuntime::NODE190(),
1649+
'node-20.0' => BuildRuntime::NODE200(),
1650+
'node-21.0' => BuildRuntime::NODE210(),
1651+
'node-22' => BuildRuntime::NODE22(),
1652+
'php-8.0' => BuildRuntime::PHP80(),
1653+
'php-8.1' => BuildRuntime::PHP81(),
1654+
'php-8.2' => BuildRuntime::PHP82(),
1655+
'php-8.3' => BuildRuntime::PHP83(),
1656+
'ruby-3.0' => BuildRuntime::RUBY30(),
1657+
'ruby-3.1' => BuildRuntime::RUBY31(),
1658+
'ruby-3.2' => BuildRuntime::RUBY32(),
1659+
'ruby-3.3' => BuildRuntime::RUBY33(),
1660+
'python-3.8' => BuildRuntime::PYTHON38(),
1661+
'python-3.9' => BuildRuntime::PYTHON39(),
1662+
'python-3.10' => BuildRuntime::PYTHON310(),
1663+
'python-3.11' => BuildRuntime::PYTHON311(),
1664+
'python-3.12' => BuildRuntime::PYTHON312(),
1665+
'python-ml-3.11' => BuildRuntime::PYTHONML311(),
1666+
'python-ml-3.12' => BuildRuntime::PYTHONML312(),
1667+
'dart-3.0' => BuildRuntime::DART30(),
1668+
'dart-3.1' => BuildRuntime::DART31(),
1669+
'dart-3.3' => BuildRuntime::DART33(),
1670+
'dart-3.5' => BuildRuntime::DART35(),
1671+
'dart-3.8' => BuildRuntime::DART38(),
1672+
'dart-3.9' => BuildRuntime::DART39(),
1673+
'dart-2.15' => BuildRuntime::DART215(),
1674+
'dart-2.16' => BuildRuntime::DART216(),
1675+
'dart-2.17' => BuildRuntime::DART217(),
1676+
'dart-2.18' => BuildRuntime::DART218(),
1677+
'dart-2.19' => BuildRuntime::DART219(),
1678+
'deno-1.21' => BuildRuntime::DENO121(),
1679+
'deno-1.24' => BuildRuntime::DENO124(),
1680+
'deno-1.35' => BuildRuntime::DENO135(),
1681+
'deno-1.40' => BuildRuntime::DENO140(),
1682+
'deno-1.46' => BuildRuntime::DENO146(),
1683+
'deno-2.0' => BuildRuntime::DENO20(),
1684+
'dotnet-6.0' => BuildRuntime::DOTNET60(),
1685+
'dotnet-7.0' => BuildRuntime::DOTNET70(),
1686+
'dotnet-8.0' => BuildRuntime::DOTNET80(),
1687+
'java-8.0' => BuildRuntime::JAVA80(),
1688+
'java-11.0' => BuildRuntime::JAVA110(),
1689+
'java-17.0' => BuildRuntime::JAVA170(),
1690+
'java-18.0' => BuildRuntime::JAVA180(),
1691+
'java-21.0' => BuildRuntime::JAVA210(),
1692+
'java-22' => BuildRuntime::JAVA22(),
1693+
'swift-5.5' => BuildRuntime::SWIFT55(),
1694+
'swift-5.8' => BuildRuntime::SWIFT58(),
1695+
'swift-5.9' => BuildRuntime::SWIFT59(),
1696+
'swift-5.10' => BuildRuntime::SWIFT510(),
1697+
'kotlin-1.6' => BuildRuntime::KOTLIN16(),
1698+
'kotlin-1.8' => BuildRuntime::KOTLIN18(),
1699+
'kotlin-1.9' => BuildRuntime::KOTLIN19(),
1700+
'kotlin-2.0' => BuildRuntime::KOTLIN20(),
1701+
'cpp-17' => BuildRuntime::CPP17(),
1702+
'cpp-20' => BuildRuntime::CPP20(),
1703+
'bun-1.0' => BuildRuntime::BUN10(),
1704+
'bun-1.1' => BuildRuntime::BUN11(),
1705+
'go-1.23' => BuildRuntime::GO123(),
1706+
'static-1' => BuildRuntime::STATIC1(),
1707+
'flutter-3.24' => BuildRuntime::FLUTTER324(),
1708+
'flutter-3.27' => BuildRuntime::FLUTTER327(),
1709+
'flutter-3.29' => BuildRuntime::FLUTTER329(),
1710+
'flutter-3.32' => BuildRuntime::FLUTTER332(),
1711+
'flutter-3.35' => BuildRuntime::FLUTTER335(),
1712+
default => throw new \Exception('Invalid Build Runtime: ' . $resource->getBuildRuntime()),
1713+
};
1714+
1715+
$framework = match ($resource->getFramework()) {
1716+
'analog' => Framework::ANALOG(),
1717+
'angular' => Framework::ANGULAR(),
1718+
'astro' => Framework::ASTRO(),
1719+
'flutter', 'flutter-web' => Framework::FLUTTER(),
1720+
'lynx' => Framework::LYNX(),
1721+
'nextjs' => Framework::NEXTJS(),
1722+
'nuxt' => Framework::NUXT(),
1723+
'react' => Framework::REACT(),
1724+
'react-native' => Framework::REACTNATIVE(),
1725+
'remix' => Framework::REMIX(),
1726+
'svelte-kit' => Framework::SVELTEKIT(),
1727+
'tanstack-start' => Framework::TANSTACKSTART(),
1728+
'vite' => Framework::VITE(),
1729+
'vue' => Framework::VUE(),
1730+
default => Framework::OTHER(),
1731+
};
1732+
1733+
$adapter = match ($resource->getAdapter()) {
1734+
'static' => Adapter::STATIC(),
1735+
'ssr' => Adapter::SSR(),
1736+
default => null,
1737+
};
1738+
1739+
$this->sites->create(
1740+
$resource->getId(),
1741+
$resource->getSiteName(),
1742+
$framework,
1743+
$buildRuntime,
1744+
$resource->getEnabled(),
1745+
$resource->getLogging(),
1746+
$resource->getTimeout(),
1747+
$resource->getInstallCommand(),
1748+
$resource->getBuildCommand(),
1749+
$resource->getOutputDirectory(),
1750+
$adapter,
1751+
fallbackFile: $resource->getFallbackFile(),
1752+
specification: $resource->getSpecification(),
1753+
);
1754+
break;
1755+
case Resource::TYPE_SITE_VARIABLE:
1756+
/** @var SiteEnvVar $resource */
1757+
$this->sites->createVariable(
1758+
$resource->getSite()->getId(),
1759+
$resource->getKey(),
1760+
$resource->getValue()
1761+
);
1762+
break;
1763+
case Resource::TYPE_SITE_DEPLOYMENT:
1764+
/** @var SiteDeployment $resource */
1765+
return $this->importSiteDeployment($resource);
1766+
}
1767+
1768+
$resource->setStatus(Resource::STATUS_SUCCESS);
1769+
1770+
return $resource;
1771+
}
1772+
1773+
/**
1774+
* @throws AppwriteException
1775+
* @throws \Exception
1776+
*/
1777+
private function importSiteDeployment(SiteDeployment $deployment): Resource
1778+
{
1779+
$siteId = $deployment->getSite()->getId();
1780+
1781+
if ($deployment->getSize() <= Transfer::STORAGE_MAX_CHUNK_SIZE) {
1782+
$response = $this->client->call(
1783+
'POST',
1784+
"/sites/{$siteId}/deployments",
1785+
[
1786+
'content-type' => 'multipart/form-data',
1787+
],
1788+
[
1789+
'siteId' => $siteId,
1790+
'code' => new \CURLFile('data://application/gzip;base64,' . base64_encode($deployment->getData()), 'application/gzip', 'deployment.tar.gz'),
1791+
'activate' => $deployment->getActivated(),
1792+
]
1793+
);
1794+
1795+
if (!\is_array($response) || !isset($response['$id'])) {
1796+
throw new \Exception('Site deployment creation failed');
1797+
}
1798+
1799+
$deployment->setStatus(Resource::STATUS_SUCCESS);
1800+
1801+
return $deployment;
1802+
}
1803+
1804+
$response = $this->client->call(
1805+
'POST',
1806+
"/sites/{$siteId}/deployments",
1807+
[
1808+
'content-type' => 'multipart/form-data',
1809+
'content-range' => 'bytes ' . ($deployment->getStart()) . '-' . ($deployment->getEnd() == ($deployment->getSize() - 1) ? $deployment->getSize() : $deployment->getEnd()) . '/' . $deployment->getSize(),
1810+
'x-appwrite-id' => $deployment->getId(),
1811+
],
1812+
[
1813+
'siteId' => $siteId,
1814+
'code' => new \CURLFile('data://application/gzip;base64,' . base64_encode($deployment->getData()), 'application/gzip', 'deployment.tar.gz'),
1815+
'activate' => $deployment->getActivated(),
1816+
]
1817+
);
1818+
1819+
if (!\is_array($response) || !isset($response['$id'])) {
1820+
throw new \Exception('Site deployment creation failed');
1821+
}
1822+
1823+
if ($deployment->getStart() === 0) {
1824+
$deployment->setId($response['$id']);
1825+
}
1826+
1827+
if ($deployment->getEnd() == ($deployment->getSize() - 1)) {
1828+
$deployment->setStatus(Resource::STATUS_SUCCESS);
1829+
} else {
1830+
$deployment->setStatus(Resource::STATUS_PENDING);
1831+
}
1832+
1833+
return $deployment;
1834+
}
16101835
}

0 commit comments

Comments
 (0)