Merge remote-tracking branch 'origin/1.8.x' into sync-mongodb

This commit is contained in:
ArnabChatterjee20k
2026-03-02 12:49:01 +05:30
5 changed files with 203 additions and 10 deletions
Generated
+10 -10
View File
@@ -5215,16 +5215,16 @@
},
{
"name": "utopia-php/vcs",
"version": "2.0.0",
"version": "2.0.1",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/vcs.git",
"reference": "058049326e04a2a0c2f0ce8ad00c7e84825aba14"
"reference": "92a1650824ba0c5e6a1bc46e622ac87c50a08920"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/058049326e04a2a0c2f0ce8ad00c7e84825aba14",
"reference": "058049326e04a2a0c2f0ce8ad00c7e84825aba14",
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/92a1650824ba0c5e6a1bc46e622ac87c50a08920",
"reference": "92a1650824ba0c5e6a1bc46e622ac87c50a08920",
"shasum": ""
},
"require": {
@@ -5258,9 +5258,9 @@
],
"support": {
"issues": "https://github.com/utopia-php/vcs/issues",
"source": "https://github.com/utopia-php/vcs/tree/2.0.0"
"source": "https://github.com/utopia-php/vcs/tree/2.0.1"
},
"time": "2026-02-25T11:36:45+00:00"
"time": "2026-02-27T12:18:49+00:00"
},
{
"name": "utopia-php/websocket",
@@ -6432,11 +6432,11 @@
},
{
"name": "phpstan/phpstan",
"version": "1.12.32",
"version": "1.12.33",
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8",
"reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8",
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/37982d6fc7cbb746dda7773530cda557cdf119e1",
"reference": "37982d6fc7cbb746dda7773530cda557cdf119e1",
"shasum": ""
},
"require": {
@@ -6481,7 +6481,7 @@
"type": "github"
}
],
"time": "2025-09-30T10:16:31+00:00"
"time": "2026-02-28T20:30:03+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -340,6 +340,8 @@ class Migrations extends Action
'files.write',
'functions.read',
'functions.write',
'sites.read',
'sites.write',
'tokens.read',
'tokens.write',
]
+32
View File
@@ -473,6 +473,38 @@ abstract class Format
break;
}
break;
case 'migrations':
switch ($method) {
case 'createAppwriteMigration':
case 'getAppwriteReport':
switch ($param) {
case 'resources':
return 'AppwriteMigrationResource';
}
break;
case 'createFirebaseMigration':
case 'getFirebaseReport':
switch ($param) {
case 'resources':
return 'FirebaseMigrationResource';
}
break;
case 'createSupabaseMigration':
case 'getSupabaseReport':
switch ($param) {
case 'resources':
return 'SupabaseMigrationResource';
}
break;
case 'createNHostMigration':
case 'getNHostReport':
switch ($param) {
case 'resources':
return 'NHostMigrationResource';
}
break;
}
break;
case 'project':
switch ($method) {
case 'getUsage':
@@ -53,6 +53,12 @@ class MigrationReport extends Model
'default' => 0,
'example' => 20,
])
->addRule(Resource::TYPE_SITE, [
'type' => self::TYPE_INTEGER,
'description' => 'Number of sites to be migrated.',
'default' => 0,
'example' => 5,
])
->addRule('size', [
'type' => self::TYPE_INTEGER,
'description' => 'Size of files to be migrated in mb.',
@@ -8,6 +8,7 @@ use Tests\E2E\Client;
use Tests\E2E\General\UsageTest;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Services\Functions\FunctionsBase;
use Utopia\Console;
use Utopia\Database\Database;
use Utopia\Database\Helpers\ID;
use Utopia\Database\Helpers\Permission;
@@ -1039,6 +1040,158 @@ trait MigrationsBase
]);
}
/**
* Sites
*/
public function testAppwriteMigrationSite(): void
{
$site = $this->client->call(Client::METHOD_POST, '/sites', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'siteId' => ID::unique(),
'name' => 'Test Site',
'framework' => 'other',
'buildRuntime' => 'node-22',
'adapter' => 'static',
'outputDirectory' => './',
]);
$this->assertEquals(201, $site['headers']['status-code'], 'Create site failed: ' . json_encode($site['body'], JSON_PRETTY_PRINT));
$this->assertNotEmpty($site['body']['$id']);
$siteId = $site['body']['$id'];
// Create deployment
$deployment = $this->client->call(Client::METHOD_POST, '/sites/' . $siteId . '/deployments', [
'content-type' => 'multipart/form-data',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'code' => $this->packageSite('static'),
'activate' => true,
]);
$this->assertEquals(202, $deployment['headers']['status-code']);
$this->assertNotEmpty($deployment['body']['$id']);
$deploymentId = $deployment['body']['$id'];
// Wait for deployment to be ready
$this->assertEventually(function () use ($siteId, $deploymentId) {
$response = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId . '/deployments/' . $deploymentId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertEquals('ready', $response['body']['status'], 'Deployment status is not ready, deployment: ' . json_encode($response['body'], JSON_PRETTY_PRINT));
}, 300000, 500);
// Create environment variable
$variable = $this->client->call(Client::METHOD_POST, '/sites/' . $siteId . '/variables', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
], [
'key' => 'TEST_VAR',
'value' => 'test_value',
]);
$this->assertEquals(201, $variable['headers']['status-code']);
// Perform migration
$result = $this->performMigrationSync([
'resources' => [
Resource::TYPE_SITE,
Resource::TYPE_SITE_DEPLOYMENT,
Resource::TYPE_SITE_VARIABLE,
],
'endpoint' => $this->webEndpoint,
'projectId' => $this->getProject()['$id'],
'apiKey' => $this->getProject()['apiKey'],
]);
$this->assertEquals('completed', $result['status']);
$this->assertEquals([Resource::TYPE_SITE, Resource::TYPE_SITE_DEPLOYMENT, Resource::TYPE_SITE_VARIABLE], $result['resources']);
foreach ([Resource::TYPE_SITE, Resource::TYPE_SITE_DEPLOYMENT, Resource::TYPE_SITE_VARIABLE] as $resource) {
$this->assertArrayHasKey($resource, $result['statusCounters']);
$this->assertEquals(0, $result['statusCounters'][$resource]['error']);
$this->assertEquals(0, $result['statusCounters'][$resource]['pending']);
$this->assertEquals(1, $result['statusCounters'][$resource]['success']);
$this->assertEquals(0, $result['statusCounters'][$resource]['processing']);
$this->assertEquals(0, $result['statusCounters'][$resource]['warning']);
}
// Verify site in destination
$response = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']);
$this->assertEquals($siteId, $response['body']['$id']);
$this->assertEquals('Test Site', $response['body']['name']);
$this->assertEquals('node-22', $response['body']['buildRuntime']);
$this->assertEquals('other', $response['body']['framework']);
$this->assertEquals('static', $response['body']['adapter']);
// Verify deployment in destination
$this->assertEventually(function () use ($siteId) {
$deployments = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId . '/deployments', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $deployments['headers']['status-code']);
$this->assertNotEmpty($deployments['body']);
$this->assertEquals(1, $deployments['body']['total']);
$this->assertEquals('ready', $deployments['body']['deployments'][0]['status'], 'Deployment status is not ready, deployment: ' . json_encode($deployments['body']['deployments'][0], JSON_PRETTY_PRINT));
}, 100000, 500);
// Verify variable in destination
$variables = $this->client->call(Client::METHOD_GET, '/sites/' . $siteId . '/variables', [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
$this->assertEquals(200, $variables['headers']['status-code']);
$this->assertEquals(1, $variables['body']['total']);
$this->assertEquals('TEST_VAR', $variables['body']['variables'][0]['key']);
// Cleanup
$this->client->call(Client::METHOD_DELETE, '/sites/' . $siteId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
'x-appwrite-key' => $this->getProject()['apiKey'],
]);
$this->client->call(Client::METHOD_DELETE, '/sites/' . $siteId, [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getDestinationProject()['$id'],
'x-appwrite-key' => $this->getDestinationProject()['apiKey'],
]);
}
private function packageSite(string $site): CURLFile
{
$stdout = '';
$stderr = '';
$folderPath = realpath(__DIR__ . '/../../../resources/sites') . "/$site";
$tarPath = "$folderPath/code.tar.gz";
Console::execute("cd $folderPath && tar --exclude code.tar.gz -czf code.tar.gz .", '', $stdout, $stderr);
return new CURLFile($tarPath, 'application/x-gzip', \basename($tarPath));
}
/**
* Import documents from a CSV file.
*/