From b9b1ec1b64c6a073d97eb5f63364c60c9c86cd03 Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Thu, 26 Feb 2026 07:49:58 +0000 Subject: [PATCH 1/4] fix: respect include inactive deployments option Use the resources array to determine whether to export only the active deployment or all deployments. When deployment/site-deployment resource type is included, export all deployments instead of only the active one. --- src/Migration/Sources/Appwrite.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Migration/Sources/Appwrite.php b/src/Migration/Sources/Appwrite.php index 47a0346..a2edd3a 100644 --- a/src/Migration/Sources/Appwrite.php +++ b/src/Migration/Sources/Appwrite.php @@ -1518,9 +1518,8 @@ protected function exportGroupFunctions(int $batchSize, array $resources): void } try { - if (\in_array(Resource::TYPE_DEPLOYMENT, $resources)) { - $this->exportDeployments($batchSize, true); - } + $exportOnlyActive = !\in_array(Resource::TYPE_DEPLOYMENT, $resources); + $this->exportDeployments($batchSize, $exportOnlyActive); } catch (\Throwable $e) { $this->addError(new Exception( Resource::TYPE_DEPLOYMENT, @@ -1549,9 +1548,8 @@ protected function exportGroupSites(int $batchSize, array $resources): void } try { - if (\in_array(Resource::TYPE_SITE_DEPLOYMENT, $resources)) { - $this->exportSiteDeployments($batchSize, true); - } + $exportOnlyActive = !\in_array(Resource::TYPE_SITE_DEPLOYMENT, $resources); + $this->exportSiteDeployments($batchSize, $exportOnlyActive); } catch (\Throwable $e) { $this->addError(new Exception( Resource::TYPE_SITE_DEPLOYMENT, From 336358d7f376c750cfc470206b19f9e9dd36fab6 Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Thu, 26 Feb 2026 10:39:05 +0000 Subject: [PATCH 2/4] fix: convert activate param to string for multipart form-data PHP booleans become '1'/'' in multipart/form-data but the API expects 'true'/'false' strings. The non-chunked function deployment path was already correct; this fixes the chunked function deployment and both site deployment paths. --- src/Migration/Destinations/Appwrite.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Migration/Destinations/Appwrite.php b/src/Migration/Destinations/Appwrite.php index 6b730a1..a128c73 100644 --- a/src/Migration/Destinations/Appwrite.php +++ b/src/Migration/Destinations/Appwrite.php @@ -1508,7 +1508,7 @@ private function importDeployment(Deployment $deployment): Resource [ 'functionId' => $functionId, 'code' => new \CURLFile('data://application/gzip;base64,' . base64_encode($deployment->getData()), 'application/gzip', 'deployment.tar.gz'), - 'activate' => $deployment->getActivated(), + 'activate' => $deployment->getActivated() ? 'true' : 'false', 'entrypoint' => $deployment->getEntrypoint(), ] ); @@ -1686,7 +1686,7 @@ private function importSiteDeployment(SiteDeployment $deployment): Resource [ 'siteId' => $siteId, 'code' => new \CURLFile('data://application/gzip;base64,' . base64_encode($deployment->getData()), 'application/gzip', 'deployment.tar.gz'), - 'activate' => $deployment->getActivated(), + 'activate' => $deployment->getActivated() ? 'true' : 'false', ] ); @@ -1710,7 +1710,7 @@ private function importSiteDeployment(SiteDeployment $deployment): Resource [ 'siteId' => $siteId, 'code' => new \CURLFile('data://application/gzip;base64,' . base64_encode($deployment->getData()), 'application/gzip', 'deployment.tar.gz'), - 'activate' => $deployment->getActivated(), + 'activate' => $deployment->getActivated() ? 'true' : 'false', ] ); From b827043cb7d799f357f37f1a4c98e9fa3e0a3ed8 Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Mon, 2 Mar 2026 09:11:44 +0000 Subject: [PATCH 3/4] fix: skip deployment import when parent resource already exists in destination When a function or site already exists in the destination, the API returns 409 and the parent resource is marked as error. Previously, deployments for that parent would still be imported, creating duplicates. Now importDeployment and importSiteDeployment check the parent status and throw an error if it failed. --- src/Migration/Destinations/Appwrite.php | 26 +++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/src/Migration/Destinations/Appwrite.php b/src/Migration/Destinations/Appwrite.php index a128c73..8c6281a 100644 --- a/src/Migration/Destinations/Appwrite.php +++ b/src/Migration/Destinations/Appwrite.php @@ -1473,7 +1473,18 @@ public function importFunctionResource(Resource $resource): Resource */ private function importDeployment(Deployment $deployment): Resource { - $functionId = $deployment->getFunction()->getId(); + $function = $deployment->getFunction(); + + if ($function->getStatus() === Resource::STATUS_ERROR) { + throw new Exception( + resourceName: $deployment->getName(), + resourceGroup: $deployment->getGroup(), + resourceId: $deployment->getId(), + message: 'Function "' . $function->getId() . '" already exists in destination', + ); + } + + $functionId = $function->getId(); $response = null; @@ -1674,7 +1685,18 @@ public function importSiteResource(Resource $resource): Resource */ private function importSiteDeployment(SiteDeployment $deployment): Resource { - $siteId = $deployment->getSite()->getId(); + $site = $deployment->getSite(); + + if ($site->getStatus() === Resource::STATUS_ERROR) { + throw new Exception( + resourceName: $deployment->getName(), + resourceGroup: $deployment->getGroup(), + resourceId: $deployment->getId(), + message: 'Site "' . $site->getId() . '" already exists in destination', + ); + } + + $siteId = $site->getId(); if ($deployment->getSize() <= Transfer::STORAGE_MAX_CHUNK_SIZE) { $response = $this->client->call( From 928e7c8f40972747b61b4e8608d90ec6a1b82556 Mon Sep 17 00:00:00 2001 From: Prem Palanisamy Date: Mon, 2 Mar 2026 09:38:02 +0000 Subject: [PATCH 4/4] fix: skip child resource import when parent resource failed --- src/Migration/Destinations/Appwrite.php | 30 +++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/Migration/Destinations/Appwrite.php b/src/Migration/Destinations/Appwrite.php index 8c6281a..b9a2527 100644 --- a/src/Migration/Destinations/Appwrite.php +++ b/src/Migration/Destinations/Appwrite.php @@ -1451,8 +1451,19 @@ public function importFunctionResource(Resource $resource): Resource break; case Resource::TYPE_ENVIRONMENT_VARIABLE: /** @var EnvVar $resource */ + $function = $resource->getFunc(); + + if ($function->getStatus() === Resource::STATUS_ERROR) { + throw new Exception( + resourceName: $resource->getName(), + resourceGroup: $resource->getGroup(), + resourceId: $resource->getId(), + message: 'Parent function "' . $function->getId() . '" failed to import', + ); + } + $this->functions->createVariable( - $resource->getFunc()->getId(), + $function->getId(), $resource->getKey(), $resource->getValue() ); @@ -1480,7 +1491,7 @@ private function importDeployment(Deployment $deployment): Resource resourceName: $deployment->getName(), resourceGroup: $deployment->getGroup(), resourceId: $deployment->getId(), - message: 'Function "' . $function->getId() . '" already exists in destination', + message: 'Parent function "' . $function->getId() . '" failed to import', ); } @@ -1663,8 +1674,19 @@ public function importSiteResource(Resource $resource): Resource break; case Resource::TYPE_SITE_VARIABLE: /** @var SiteEnvVar $resource */ + $site = $resource->getSite(); + + if ($site->getStatus() === Resource::STATUS_ERROR) { + throw new Exception( + resourceName: $resource->getName(), + resourceGroup: $resource->getGroup(), + resourceId: $resource->getId(), + message: 'Parent site "' . $site->getId() . '" failed to import', + ); + } + $this->sites->createVariable( - $resource->getSite()->getId(), + $site->getId(), $resource->getKey(), $resource->getValue() ); @@ -1692,7 +1714,7 @@ private function importSiteDeployment(SiteDeployment $deployment): Resource resourceName: $deployment->getName(), resourceGroup: $deployment->getGroup(), resourceId: $deployment->getId(), - message: 'Site "' . $site->getId() . '" already exists in destination', + message: 'Parent site "' . $site->getId() . '" failed to import', ); }