mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Revert "Features with schema changes"
This commit is contained in:
+7
-7
@@ -111,7 +111,7 @@ $ git push origin [name_of_your_new_branch]
|
||||
|
||||
## Setup From Source
|
||||
|
||||
To set up a working **development environment**, just fork the project git repository and install the backend and frontend dependencies using the proper package manager and run the docker-compose stack.
|
||||
To set up a working **development environment**, just fork the project git repository and install the backend and frontend dependencies using the proper package manager and create run the docker-compose stack.
|
||||
|
||||
> If you just want to install Appwrite for day-to-day use and not as a contributor, you can reference the [installation guide](https://github.com/appwrite/appwrite#installation), the [getting started guide](https://appwrite.io/docs/quick-starts), or the main [README](README.md) file.
|
||||
|
||||
@@ -173,12 +173,12 @@ Learn more at our [Technology Stack](#technology-stack) section.
|
||||
- [MVVM](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93viewmodel) - Appwrite console architecture
|
||||
|
||||
##### Container Namespace Conventions
|
||||
To keep our services easy to understand within Docker we follow a naming convention for all our containers depending on its intended use.
|
||||
To keep our services easy to understand within Docker we follow a naming convention for all our containers depending on it's intended use.
|
||||
|
||||
`appwrite-worker-X` - Workers (`src/Appwrite/Platform/Workers/*`)
|
||||
`appwrite-task-X` - Tasks (`src/Appwrite/Platform/Tasks/*`)
|
||||
|
||||
Other containers should be named the same as their service, for example `redis` should just be called `redis`.
|
||||
Other containes should be named the same as their service, for example `redis` should just be called `redis`.
|
||||
|
||||
##### Security
|
||||
|
||||
@@ -189,7 +189,7 @@ Other containers should be named the same as their service, for example `redis`
|
||||
|
||||
## Modules
|
||||
|
||||
As Appwrite grows, we noticed approach of having all service endpoints in `app/controllers/api/[service].php` is not maintainable. Not only it creates massive files, it also doesn't contain all product's features such as workers or tasks. While there might still be some occurrences of those controller files, we avoid it in all new development, and gradually migrate existing controllers to **HTTP modules**.
|
||||
As Appwrite grows, we noticed approach of having all service endpoints in `app/controllers/api/[service].php` is not maintainable. Not only it creates massive files, it also doesnt contain all product's features such as workers or tasks. While there might still be some occurances of those controller files, we avoid it in all new development, and gradually migrate existing controllers to **HTTP modules**.
|
||||
|
||||
### HTTP Endpoints
|
||||
|
||||
@@ -204,7 +204,7 @@ Tips and tricks:
|
||||
1. If endpoint doesn't have resource, use service name as resource name too
|
||||
> Example: `Modules/Sites/Http/Sites/Get.php`
|
||||
|
||||
2. If there are multiple resources, use them all in folder structure
|
||||
2. If there are multiple resources, use then all in folder structure
|
||||
> Example: `Modules/Sites/Http/Deployments/Builds/Create.php`
|
||||
|
||||
3. Action can only be `Get`, `Create`, `Update`, `Delete` or `XList`
|
||||
@@ -395,7 +395,7 @@ These are the current metrics we collect usage stats for:
|
||||
|
||||
> Note: The curly brackets in the metric name represents a template and is replaced with a value when the metric is processed.
|
||||
|
||||
Metrics are collected within 3 scopes Daily, monthly, and infinity. Adding new usage metric in order to aggregate usage stats is very simple, but very much dependent on where do you want to collect
|
||||
Metrics are collected within 3 scopes Daily, monthly, an infinity. Adding new usage metric in order to aggregate usage stats is very simple, but very much dependent on where do you want to collect
|
||||
statistics ,via API or via background worker. For both cases you will need to add a `const` variable in `app/init.php` under the usage metrics list using the naming convention `METRIC_<RESOURCE_NAME>` as shown below.
|
||||
|
||||
```php
|
||||
@@ -661,7 +661,7 @@ docker compose exec redis redis-cli FLUSHALL
|
||||
|
||||
## Using preview domains locally
|
||||
|
||||
Appwrite Functions are automatically given a domain you can visit to execute the function. This domain has format `[SOMETHING].functions.localhost` unless you changed `_APP_DOMAIN_FUNCTIONS` environment variable. This default value works great when running Appwrite locally, but it can be impossible to use preview domains with Cloud workspaces such as Gitpod or GitHub Codespaces.
|
||||
Appwrite Functions are automatically given a domain you can visit to execute the function. This domain has format `[SOMETHING].functions.localhost` unless you changed `_APP_DOMAIN_FUNCTIONS` environment variable. This default value works great when running Appwrite locally, but it can be impossible to use preview domains with Cloud woekspaces such as Gitpod or GitHub Codespaces.
|
||||
|
||||
To use preview domains on Cloud workspaces, you can visit hostname provided by them, and supply function's preview domain as URL parameter:
|
||||
|
||||
|
||||
@@ -777,7 +777,6 @@ return [
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
// At the moment, always empty (no runtime supports it yet)
|
||||
'array' => false,
|
||||
'$id' => ID::custom('startCommand'),
|
||||
'type' => Database::VAR_STRING,
|
||||
@@ -788,6 +787,17 @@ return [
|
||||
'default' => null,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'array' => false,
|
||||
'$id' => ID::custom('specification'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 128,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'array' => false,
|
||||
'$id' => ID::custom('buildSpecification'),
|
||||
@@ -1247,18 +1257,7 @@ return [
|
||||
],
|
||||
[
|
||||
'array' => false,
|
||||
'$id' => ID::custom('buildSpecification'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 128,
|
||||
'signed' => false,
|
||||
'required' => false,
|
||||
'default' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
'filters' => [],
|
||||
],
|
||||
[
|
||||
'array' => false,
|
||||
'$id' => ID::custom('runtimeSpecification'),
|
||||
'$id' => ID::custom('specification'),
|
||||
'type' => Database::VAR_STRING,
|
||||
'format' => '',
|
||||
'size' => 128,
|
||||
|
||||
@@ -30,8 +30,6 @@ use Appwrite\Utopia\Response\Filters\V16 as ResponseV16;
|
||||
use Appwrite\Utopia\Response\Filters\V17 as ResponseV17;
|
||||
use Appwrite\Utopia\Response\Filters\V18 as ResponseV18;
|
||||
use Appwrite\Utopia\Response\Filters\V19 as ResponseV19;
|
||||
use Appwrite\Utopia\Response\Filters\V20 as ResponseV20;
|
||||
use Appwrite\Utopia\Response\Filters\V21 as ResponseV21;
|
||||
use Appwrite\Utopia\View;
|
||||
use Executor\Executor;
|
||||
use MaxMind\Db\Reader;
|
||||
@@ -323,8 +321,7 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S
|
||||
};
|
||||
|
||||
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
|
||||
// TODO: backwards-compatibility dual-read, remove eventually.
|
||||
$spec = Config::getParam('specifications')[$resource->getAttribute('runtimeSpecification', $resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT))];
|
||||
$spec = Config::getParam('specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)];
|
||||
|
||||
$runtime = match ($type) {
|
||||
'function' => $runtimes[$resource->getAttribute('runtime')] ?? null,
|
||||
@@ -554,10 +551,6 @@ function router(Http $utopia, Database $dbForPlatform, callable $getProjectDB, S
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($deployment->getAttribute('startCommand', ''))) {
|
||||
$startCommand = 'cd /usr/local/server/src/function/ && ' . $deployment->getAttribute('startCommand', '');
|
||||
}
|
||||
|
||||
$runtimeEntrypoint = match ($version) {
|
||||
'v2' => '',
|
||||
default => "cp /tmp/code.$extension /mnt/code/code.$extension && nohup helpers/start.sh \"$startCommand\"",
|
||||
@@ -939,23 +932,17 @@ Http::init()
|
||||
*/
|
||||
$responseFormat = $request->getHeader('x-appwrite-response-format', System::getEnv('_APP_SYSTEM_RESPONSE_FORMAT', ''));
|
||||
if ($responseFormat) {
|
||||
if (version_compare($responseFormat, '1.9.0', '<')) {
|
||||
$response->addFilter(new ResponseV21());
|
||||
}
|
||||
if (version_compare($responseFormat, '1.8.0', '<')) {
|
||||
$response->addFilter(new ResponseV20());
|
||||
}
|
||||
if (version_compare($responseFormat, '1.7.0', '<')) {
|
||||
$response->addFilter(new ResponseV19());
|
||||
}
|
||||
if (version_compare($responseFormat, '1.6.0', '<')) {
|
||||
$response->addFilter(new ResponseV18());
|
||||
if (version_compare($responseFormat, '1.4.0', '<')) {
|
||||
$response->addFilter(new ResponseV16());
|
||||
}
|
||||
if (version_compare($responseFormat, '1.5.0', '<')) {
|
||||
$response->addFilter(new ResponseV17());
|
||||
}
|
||||
if (version_compare($responseFormat, '1.4.0', '<')) {
|
||||
$response->addFilter(new ResponseV16());
|
||||
if (version_compare($responseFormat, '1.6.0', '<')) {
|
||||
$response->addFilter(new ResponseV18());
|
||||
}
|
||||
if (version_compare($responseFormat, '1.7.0', '<')) {
|
||||
$response->addFilter(new ResponseV19());
|
||||
}
|
||||
if (version_compare($responseFormat, APP_VERSION_STABLE, '>')) {
|
||||
$warnings[] = "The current SDK is built for Appwrite " . $responseFormat . ". However, the current Appwrite server version is " . APP_VERSION_STABLE . ". Please downgrade your SDK to match the Appwrite version: https://appwrite.io/docs/sdks";
|
||||
|
||||
@@ -11,7 +11,6 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Permission;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
use Utopia\Database\Validator\Datetime as DatetimeValidator;
|
||||
use Utopia\Database\Validator\UID;
|
||||
use Utopia\Http\Http;
|
||||
use Utopia\Locale\Locale;
|
||||
@@ -220,53 +219,6 @@ Http::post('/v1/mock/api-key-unprefixed')
|
||||
->dynamic($key, Response::MODEL_KEY);
|
||||
});
|
||||
|
||||
Http::post('/v1/mock/time-travels')
|
||||
->desc('Create a time-travel to change $createdAt')
|
||||
->groups(['mock', 'api'])
|
||||
->label('scope', 'public')
|
||||
->label('docs', false)
|
||||
->param('projectId', '', new UID(), 'Project ID.')
|
||||
->param('resourceType', '', new WhiteList(['deployment']), 'Type of resource.')
|
||||
->param('resourceId', '', new UID(), 'ID of resource.')
|
||||
->param('createdAt', '', new DatetimeValidator(), 'New value for $createdAt')
|
||||
->inject('response')
|
||||
->inject('getProjectDB')
|
||||
->inject('dbForPlatform')
|
||||
->action(function (string $projectId, string $resourceType, string $resourceId, string $createdAt, Response $response, callable $getProjectDB, Database $dbForPlatform) {
|
||||
$isDevelopment = System::getEnv('_APP_ENV', 'development') === 'development';
|
||||
|
||||
if (!$isDevelopment) {
|
||||
throw new Exception(Exception::GENERAL_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
$project = $dbForPlatform->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$collection = match($resourceType) {
|
||||
'deployment' => 'deployments',
|
||||
default => throw new Exception(Exception::GENERAL_NOT_IMPLEMENTED)
|
||||
};
|
||||
|
||||
/** @var Database $dbForProject */
|
||||
$dbForProject = $getProjectDB($project);
|
||||
|
||||
$resource = $dbForProject->getDocument($collection, $resourceId);
|
||||
if ($resource->isEmpty()) {
|
||||
throw new Exception(Exception::GENERAL_ARGUMENT_INVALID, 'Resource not found');
|
||||
}
|
||||
|
||||
$update = new Document([
|
||||
'$createdAt' => $createdAt,
|
||||
]);
|
||||
|
||||
$dbForProject->withPreserveDates(fn () => $dbForProject->updateDocument($collection, $resourceId, $update));
|
||||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
Http::get('/v1/mock/github/callback')
|
||||
->desc('Create installation document using GitHub installation id')
|
||||
->groups(['mock', 'api', 'vcs'])
|
||||
|
||||
@@ -93,7 +93,6 @@ const APP_SOCIAL_YOUTUBE = 'https://www.youtube.com/c/appwrite?sub_confirmation=
|
||||
const APP_COMPUTE_CPUS_DEFAULT = 0.5;
|
||||
const APP_COMPUTE_MEMORY_DEFAULT = 512;
|
||||
const APP_COMPUTE_SPECIFICATION_DEFAULT = Specification::S_1VCPU_512MB;
|
||||
const APP_COMPUTE_DEPLOYMENT_MAX_RETENTION = 100 * 365; // 100 years
|
||||
const APP_SDK_PLATFORM_SERVER = 'server';
|
||||
const APP_SDK_PLATFORM_CLIENT = 'client';
|
||||
const APP_SDK_PLATFORM_CONSOLE = 'console';
|
||||
|
||||
Generated
+66
-66
@@ -2708,16 +2708,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
"version": "v7.4.6",
|
||||
"version": "v7.4.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client.git",
|
||||
"reference": "2bde8afd5ab2fe0b05a9c2d4c3c0e28ceb98a154"
|
||||
"reference": "84bb634857a893cc146cceb467e31b3f02c5fe9f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/2bde8afd5ab2fe0b05a9c2d4c3c0e28ceb98a154",
|
||||
"reference": "2bde8afd5ab2fe0b05a9c2d4c3c0e28ceb98a154",
|
||||
"url": "https://api.github.com/repos/symfony/http-client/zipball/84bb634857a893cc146cceb467e31b3f02c5fe9f",
|
||||
"reference": "84bb634857a893cc146cceb467e31b3f02c5fe9f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2785,7 +2785,7 @@
|
||||
"http"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.4.6"
|
||||
"source": "https://github.com/symfony/http-client/tree/v7.4.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2805,7 +2805,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-18T09:46:18+00:00"
|
||||
"time": "2026-01-27T16:16:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
@@ -3850,16 +3850,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "5.3.5",
|
||||
"version": "5.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "8227f5739ea510735dc2fab464ea09ef5f9cf4d7"
|
||||
"reference": "ba1ee9cb2c7624d0fada782b285bd9958a07bbe5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/8227f5739ea510735dc2fab464ea09ef5f9cf4d7",
|
||||
"reference": "8227f5739ea510735dc2fab464ea09ef5f9cf4d7",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/ba1ee9cb2c7624d0fada782b285bd9958a07bbe5",
|
||||
"reference": "ba1ee9cb2c7624d0fada782b285bd9958a07bbe5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3902,9 +3902,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/5.3.5"
|
||||
"source": "https://github.com/utopia-php/database/tree/5.3.4"
|
||||
},
|
||||
"time": "2026-03-04T08:18:13+00:00"
|
||||
"time": "2026-02-24T00:37:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/detector",
|
||||
@@ -4058,16 +4058,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
"version": "1.0.5",
|
||||
"version": "1.0.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/domains.git",
|
||||
"reference": "0edf6bb2b07f30db849a267027077bf5abb994c6"
|
||||
"reference": "b4896a6746f0fbe29dfd5e32f7790bd94c1af1e6"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/domains/zipball/0edf6bb2b07f30db849a267027077bf5abb994c6",
|
||||
"reference": "0edf6bb2b07f30db849a267027077bf5abb994c6",
|
||||
"url": "https://api.github.com/repos/utopia-php/domains/zipball/b4896a6746f0fbe29dfd5e32f7790bd94c1af1e6",
|
||||
"reference": "b4896a6746f0fbe29dfd5e32f7790bd94c1af1e6",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4114,9 +4114,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/domains/issues",
|
||||
"source": "https://github.com/utopia-php/domains/tree/1.0.5"
|
||||
"source": "https://github.com/utopia-php/domains/tree/1.0.2"
|
||||
},
|
||||
"time": "2026-03-03T09:20:50+00:00"
|
||||
"time": "2026-02-25T08:18:25+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/dsn",
|
||||
@@ -4267,16 +4267,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/framework",
|
||||
"version": "0.33.41",
|
||||
"version": "0.33.40",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/http.git",
|
||||
"reference": "0f3bf2377c867e547c929c3733b8224afee6ef06"
|
||||
"reference": "0ba25e1282c6a2f849053f7ccf28d567c2c321b1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/0f3bf2377c867e547c929c3733b8224afee6ef06",
|
||||
"reference": "0f3bf2377c867e547c929c3733b8224afee6ef06",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/0ba25e1282c6a2f849053f7ccf28d567c2c321b1",
|
||||
"reference": "0ba25e1282c6a2f849053f7ccf28d567c2c321b1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4310,9 +4310,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/http/issues",
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.41"
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.40"
|
||||
},
|
||||
"time": "2026-02-24T12:01:28+00:00"
|
||||
"time": "2026-02-19T13:00:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
@@ -4517,16 +4517,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "1.6.3",
|
||||
"version": "1.6.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "c2d016944cb029fa5ff822ceee704785a06ef289"
|
||||
"reference": "037bf4b3813d44f1b0990bc124e35b501ed27fca"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/c2d016944cb029fa5ff822ceee704785a06ef289",
|
||||
"reference": "c2d016944cb029fa5ff822ceee704785a06ef289",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/037bf4b3813d44f1b0990bc124e35b501ed27fca",
|
||||
"reference": "037bf4b3813d44f1b0990bc124e35b501ed27fca",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4566,9 +4566,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.6.3"
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.6.2"
|
||||
},
|
||||
"time": "2026-03-04T07:08:22+00:00"
|
||||
"time": "2026-02-25T12:00:11+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
@@ -5438,16 +5438,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.11.4",
|
||||
"version": "1.11.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "898bc431c2b5d304cede3400627b6b58a82e123d"
|
||||
"reference": "45d22c0107a53bb9a0a4e39db0e738d461631d11"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/898bc431c2b5d304cede3400627b6b58a82e123d",
|
||||
"reference": "898bc431c2b5d304cede3400627b6b58a82e123d",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/45d22c0107a53bb9a0a4e39db0e738d461631d11",
|
||||
"reference": "45d22c0107a53bb9a0a4e39db0e738d461631d11",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5483,9 +5483,9 @@
|
||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.11.4"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.11.3"
|
||||
},
|
||||
"time": "2026-03-03T05:25:21+00:00"
|
||||
"time": "2026-02-27T06:54:59+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brianium/paratest",
|
||||
@@ -6432,11 +6432,11 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "1.12.33",
|
||||
"version": "1.12.32",
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/37982d6fc7cbb746dda7773530cda557cdf119e1",
|
||||
"reference": "37982d6fc7cbb746dda7773530cda557cdf119e1",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/2770dcdf5078d0b0d53f94317e06affe88419aa8",
|
||||
"reference": "2770dcdf5078d0b0d53f94317e06affe88419aa8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -6481,7 +6481,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-28T20:30:03+00:00"
|
||||
"time": "2025-09-30T10:16:31+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@@ -8031,16 +8031,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v8.0.6",
|
||||
"version": "v8.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/console.git",
|
||||
"reference": "488285876e807a4777f074041d8bb508623419fa"
|
||||
"reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/488285876e807a4777f074041d8bb508623419fa",
|
||||
"reference": "488285876e807a4777f074041d8bb508623419fa",
|
||||
"url": "https://api.github.com/repos/symfony/console/zipball/ace03c4cf9805080ff40cbeec69fca180c339a3b",
|
||||
"reference": "ace03c4cf9805080ff40cbeec69fca180c339a3b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8097,7 +8097,7 @@
|
||||
"terminal"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.6"
|
||||
"source": "https://github.com/symfony/console/tree/v8.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8117,20 +8117,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-25T16:59:43+00:00"
|
||||
"time": "2026-01-13T13:06:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "v8.0.6",
|
||||
"version": "v8.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/filesystem.git",
|
||||
"reference": "7bf9162d7a0dff98d079b72948508fa48018a770"
|
||||
"reference": "d937d400b980523dc9ee946bb69972b5e619058d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/7bf9162d7a0dff98d079b72948508fa48018a770",
|
||||
"reference": "7bf9162d7a0dff98d079b72948508fa48018a770",
|
||||
"url": "https://api.github.com/repos/symfony/filesystem/zipball/d937d400b980523dc9ee946bb69972b5e619058d",
|
||||
"reference": "d937d400b980523dc9ee946bb69972b5e619058d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8167,7 +8167,7 @@
|
||||
"description": "Provides basic utilities for the filesystem",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/filesystem/tree/v8.0.6"
|
||||
"source": "https://github.com/symfony/filesystem/tree/v8.0.1"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8187,20 +8187,20 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-25T16:59:43+00:00"
|
||||
"time": "2025-12-01T09:13:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/finder",
|
||||
"version": "v8.0.6",
|
||||
"version": "v8.0.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/finder.git",
|
||||
"reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c"
|
||||
"reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/441404f09a54de6d1bd6ad219e088cdf4c91f97c",
|
||||
"reference": "441404f09a54de6d1bd6ad219e088cdf4c91f97c",
|
||||
"url": "https://api.github.com/repos/symfony/finder/zipball/8bd576e97c67d45941365bf824e18dc8538e6eb0",
|
||||
"reference": "8bd576e97c67d45941365bf824e18dc8538e6eb0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8235,7 +8235,7 @@
|
||||
"description": "Finds files and directories via an intuitive fluent interface",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/finder/tree/v8.0.6"
|
||||
"source": "https://github.com/symfony/finder/tree/v8.0.5"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8255,7 +8255,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-01-29T09:41:02+00:00"
|
||||
"time": "2026-01-26T15:08:38+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/options-resolver",
|
||||
@@ -8725,16 +8725,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/string",
|
||||
"version": "v8.0.6",
|
||||
"version": "v8.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/string.git",
|
||||
"reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4"
|
||||
"reference": "758b372d6882506821ed666032e43020c4f57194"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/6c9e1108041b5dce21a9a4984b531c4923aa9ec4",
|
||||
"reference": "6c9e1108041b5dce21a9a4984b531c4923aa9ec4",
|
||||
"url": "https://api.github.com/repos/symfony/string/zipball/758b372d6882506821ed666032e43020c4f57194",
|
||||
"reference": "758b372d6882506821ed666032e43020c4f57194",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -8791,7 +8791,7 @@
|
||||
"utf8"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/string/tree/v8.0.6"
|
||||
"source": "https://github.com/symfony/string/tree/v8.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -8811,7 +8811,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-02-09T10:14:57+00:00"
|
||||
"time": "2026-01-12T12:37:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "textalk/websocket",
|
||||
@@ -9043,7 +9043,7 @@
|
||||
],
|
||||
"aliases": [],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {},
|
||||
"stability-flags": [],
|
||||
"prefer-stable": true,
|
||||
"prefer-lowest": false,
|
||||
"platform": {
|
||||
@@ -9067,5 +9067,5 @@
|
||||
"platform-overrides": {
|
||||
"php": "8.3"
|
||||
},
|
||||
"plugin-api-version": "2.9.0"
|
||||
"plugin-api-version": "2.6.0"
|
||||
}
|
||||
|
||||
@@ -180,8 +180,7 @@ class Create extends Base
|
||||
|
||||
$version = $function->getAttribute('version', 'v2');
|
||||
$runtimes = Config::getParam($version === 'v2' ? 'runtimes-v2' : 'runtimes', []);
|
||||
// TODO: backwards-compatibility dual-read, remove eventually.
|
||||
$spec = Config::getParam('specifications')[$function->getAttribute('runtimeSpecification', $function->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT))];
|
||||
$spec = Config::getParam('specifications')[$function->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)];
|
||||
|
||||
$runtime = (isset($runtimes[$function->getAttribute('runtime', '')])) ? $runtimes[$function->getAttribute('runtime', '')] : null;
|
||||
|
||||
@@ -421,11 +420,6 @@ class Create extends Base
|
||||
try {
|
||||
$version = $function->getAttribute('version', 'v2');
|
||||
$command = $runtime['startCommand'];
|
||||
|
||||
if (!empty($deployment->getAttribute('startCommand', ''))) {
|
||||
$command = 'cd /usr/local/server/src/function/ && ' . $deployment->getAttribute('startCommand', '');
|
||||
}
|
||||
|
||||
$source = $deployment->getAttribute('buildPath', '');
|
||||
$extension = str_ends_with($source, '.tar') ? 'tar' : 'tar.gz';
|
||||
$command = $version === 'v2' ? '' : "cp /tmp/code.$extension /mnt/code/code.$extension && nohup helpers/start.sh \"$command\"";
|
||||
|
||||
@@ -93,23 +93,16 @@ class Create extends Base
|
||||
->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function.', true)
|
||||
->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.', true)
|
||||
->param('providerRootDirectory', '', new Text(128, 0), 'Path to function code in the linked repo.', true)
|
||||
->param('buildSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
->param('specification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
$plan,
|
||||
Config::getParam('specifications', []),
|
||||
System::getEnv('_APP_COMPUTE_CPUS', 0),
|
||||
System::getEnv('_APP_COMPUTE_MEMORY', 0)
|
||||
), 'Build specification for the function deployments.', true, ['plan'])
|
||||
->param('runtimeSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
$plan,
|
||||
Config::getParam('specifications', []),
|
||||
System::getEnv('_APP_COMPUTE_CPUS', 0),
|
||||
System::getEnv('_APP_COMPUTE_MEMORY', 0)
|
||||
), 'Runtime specification for the function executions.', true, ['plan'])
|
||||
), 'Runtime specification for the function and builds.', true, ['plan'])
|
||||
->param('templateRepository', '', new Text(128, 0), 'Repository name of the template.', true, deprecated: true)
|
||||
->param('templateOwner', '', new Text(128, 0), 'The name of the owner of the template.', true, deprecated: true)
|
||||
->param('templateRootDirectory', '', new Text(128, 0), 'Path to function code in the template repo.', true, deprecated: true)
|
||||
->param('templateVersion', '', new Text(128, 0), 'Version (tag) for the repo linked to the function template.', true, deprecated: true)
|
||||
->param('deploymentRetention', 0, new Range(0, APP_COMPUTE_DEPLOYMENT_MAX_RETENTION), 'Days to keep non-active deployments before deletion. Value 0 means all deployments will be kept.', true)
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('timelimit')
|
||||
@@ -145,13 +138,11 @@ class Create extends Base
|
||||
string $providerBranch,
|
||||
bool $providerSilentMode,
|
||||
string $providerRootDirectory,
|
||||
string $buildSpecification,
|
||||
string $runtimeSpecification,
|
||||
string $specification,
|
||||
string $templateRepository,
|
||||
string $templateOwner,
|
||||
string $templateRootDirectory,
|
||||
string $templateVersion,
|
||||
int $deploymentRetention,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
callable $timelimit,
|
||||
@@ -224,7 +215,6 @@ class Create extends Base
|
||||
'logging' => $logging,
|
||||
'name' => $name,
|
||||
'runtime' => $runtime,
|
||||
'deploymentRetention' => $deploymentRetention,
|
||||
'deploymentInternalId' => '',
|
||||
'deploymentId' => '',
|
||||
'events' => $events,
|
||||
@@ -247,8 +237,9 @@ class Create extends Base
|
||||
'providerBranch' => $providerBranch,
|
||||
'providerRootDirectory' => $providerRootDirectory,
|
||||
'providerSilentMode' => $providerSilentMode,
|
||||
'buildSpecification' => $buildSpecification,
|
||||
'runtimeSpecification' => $runtimeSpecification,
|
||||
'specification' => $specification,
|
||||
'buildSpecification' => $specification,
|
||||
'runtimeSpecification' => $specification,
|
||||
]));
|
||||
} catch (DuplicateException) {
|
||||
throw new Exception(Exception::FUNCTION_ALREADY_EXISTS);
|
||||
|
||||
@@ -87,19 +87,12 @@ class Update extends Base
|
||||
->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the function', true)
|
||||
->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the function? In silent mode, comments will not be made on commits and pull requests.', true)
|
||||
->param('providerRootDirectory', '', new Text(128, 0), 'Path to function code in the linked repo.', true)
|
||||
->param('buildSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
->param('specification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
$plan,
|
||||
Config::getParam('specifications', []),
|
||||
System::getEnv('_APP_COMPUTE_CPUS', 0),
|
||||
System::getEnv('_APP_COMPUTE_MEMORY', 0)
|
||||
), 'Build specification for the function deployments.', true, ['plan'])
|
||||
->param('runtimeSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
$plan,
|
||||
Config::getParam('specifications', []),
|
||||
System::getEnv('_APP_COMPUTE_CPUS', 0),
|
||||
System::getEnv('_APP_COMPUTE_MEMORY', 0)
|
||||
), 'Runtime specification for the function executions.', true, ['plan'])
|
||||
->param('deploymentRetention', 0, new Range(0, APP_COMPUTE_DEPLOYMENT_MAX_RETENTION), 'Days to keep non-active deployments before deletion. Value 0 means all deployments will be kept.', true)
|
||||
), 'Runtime specification for the function and builds.', true, ['plan'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -131,9 +124,7 @@ class Update extends Base
|
||||
string $providerBranch,
|
||||
bool $providerSilentMode,
|
||||
string $providerRootDirectory,
|
||||
string $buildSpecification,
|
||||
string $runtimeSpecification,
|
||||
int $deploymentRetention,
|
||||
string $specification,
|
||||
Request $request,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
@@ -218,7 +209,7 @@ class Update extends Base
|
||||
'resourceId' => $function->getId(),
|
||||
'resourceInternalId' => $function->getSequence(),
|
||||
'resourceType' => 'function',
|
||||
'providerPullRequestIds' => [],
|
||||
'providerPullRequestIds' => []
|
||||
]));
|
||||
|
||||
$repositoryId = $repository->getId();
|
||||
@@ -238,24 +229,13 @@ class Update extends Base
|
||||
}
|
||||
|
||||
// Enforce Cold Start if spec limits change.
|
||||
if (!empty($function->getAttribute('deploymentId'))) {
|
||||
$specsChanged = false;
|
||||
// TODO: backwards-compatibility dual-read, remove eventually.
|
||||
if ($function->getAttribute('runtimeSpecification', $function->getAttribute('specification')) !== $runtimeSpecification) {
|
||||
$specsChanged = true;
|
||||
// TODO: backwards-compatibility dual-read, remove eventually.
|
||||
} elseif ($function->getAttribute('buildSpecification', $function->getAttribute('specification')) !== $buildSpecification) {
|
||||
$specsChanged = true;
|
||||
}
|
||||
|
||||
if ($specsChanged) {
|
||||
try {
|
||||
$executor->deleteRuntime($project->getId(), $function->getAttribute('deploymentId'));
|
||||
} catch (\Throwable $th) {
|
||||
// Don't throw if the deployment doesn't exist
|
||||
if ($th->getCode() !== 404) {
|
||||
throw $th;
|
||||
}
|
||||
if ($function->getAttribute('specification') !== $specification && !empty($function->getAttribute('deploymentId'))) {
|
||||
try {
|
||||
$executor->deleteRuntime($project->getId(), $function->getAttribute('deploymentId'));
|
||||
} catch (\Throwable $th) {
|
||||
// Don't throw if the deployment doesn't exist
|
||||
if ($th->getCode() !== 404) {
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -273,7 +253,8 @@ class Update extends Base
|
||||
'entrypoint' => $entrypoint,
|
||||
'commands' => $commands,
|
||||
'scopes' => $scopes,
|
||||
'deploymentRetention' => $deploymentRetention,
|
||||
'deploymentRetention' => 0,
|
||||
'startCommand' => '',
|
||||
'installationId' => $installation->getId(),
|
||||
'installationInternalId' => $installation->getSequence(),
|
||||
'providerRepositoryId' => $providerRepositoryId,
|
||||
@@ -282,8 +263,9 @@ class Update extends Base
|
||||
'providerBranch' => $providerBranch,
|
||||
'providerRootDirectory' => $providerRootDirectory,
|
||||
'providerSilentMode' => $providerSilentMode,
|
||||
'buildSpecification' => $buildSpecification,
|
||||
'runtimeSpecification' => $runtimeSpecification,
|
||||
'specification' => $specification,
|
||||
'buildSpecification' => $specification,
|
||||
'runtimeSpecification' => $specification,
|
||||
'search' => implode(' ', [$functionId, $name, $runtime]),
|
||||
])));
|
||||
|
||||
|
||||
@@ -255,8 +255,7 @@ class Builds extends Action
|
||||
$version = $this->getVersion($resource);
|
||||
$runtime = $this->getRuntime($resource, $version);
|
||||
|
||||
// TODO: backwards-compatibility dual-read, remove eventually.
|
||||
$spec = Config::getParam('specifications')[$resource->getAttribute('buildSpecification', $resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT))];
|
||||
$spec = Config::getParam('specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)];
|
||||
|
||||
if ($resource->getCollection() === 'functions' && \is_null($runtime)) {
|
||||
throw new \Exception('Runtime "' . $resource->getAttribute('runtime', '') . '" is not supported');
|
||||
@@ -1190,8 +1189,7 @@ class Builds extends Action
|
||||
|
||||
protected function sendUsage(Document $resource, Document $deployment, Document $project, StatsUsage $queue): void
|
||||
{
|
||||
// TODO: backwards-compatibility dual-read, remove eventually.
|
||||
$spec = Config::getParam('specifications')[$resource->getAttribute('buildSpecification', $resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT))];
|
||||
$spec = Config::getParam('specifications')[$resource->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)];
|
||||
|
||||
switch ($deployment->getAttribute('status')) {
|
||||
case 'ready':
|
||||
|
||||
@@ -68,7 +68,6 @@ class Create extends Base
|
||||
->param('timeout', 30, new Range(1, (int) System::getEnv('_APP_SITES_TIMEOUT', 30)), 'Maximum request time in seconds.', true)
|
||||
->param('installCommand', '', new Text(8192, 0), 'Install Command.', true)
|
||||
->param('buildCommand', '', new Text(8192, 0), 'Build Command.', true)
|
||||
->param('startCommand', '', new Text(8192, 0), 'Custom start command. Leave empty to use default.', true)
|
||||
->param('outputDirectory', '', new Text(8192, 0), 'Output Directory for site.', true)
|
||||
->param('buildRuntime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Runtime to use during build step.')
|
||||
->param('adapter', '', new WhiteList(['static', 'ssr']), 'Framework adapter defining rendering strategy. Allowed values are: static, ssr', true)
|
||||
@@ -78,19 +77,12 @@ class Create extends Base
|
||||
->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the site.', true)
|
||||
->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the site? In silent mode, comments will not be made on commits and pull requests.', true)
|
||||
->param('providerRootDirectory', '', new Text(128, 0), 'Path to site code in the linked repo.', true)
|
||||
->param('buildSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
->param('specification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
$plan,
|
||||
Config::getParam('specifications', []),
|
||||
System::getEnv('_APP_COMPUTE_CPUS', 0),
|
||||
System::getEnv('_APP_COMPUTE_MEMORY', 0)
|
||||
), 'Build specification for the site deployments.', true, ['plan'])
|
||||
->param('runtimeSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
$plan,
|
||||
Config::getParam('specifications', []),
|
||||
System::getEnv('_APP_COMPUTE_CPUS', 0),
|
||||
System::getEnv('_APP_COMPUTE_MEMORY', 0)
|
||||
), 'Runtime specification for the SSR executions.', true, ['plan'])
|
||||
->param('deploymentRetention', 0, new Range(0, APP_COMPUTE_DEPLOYMENT_MAX_RETENTION), 'Days to keep non-active deployments before deletion. Value 0 means all deployments will be kept.', true)
|
||||
), 'Framework specification for the site and builds.', true, ['plan'])
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
@@ -108,7 +100,6 @@ class Create extends Base
|
||||
int $timeout,
|
||||
string $installCommand,
|
||||
string $buildCommand,
|
||||
string $startCommand,
|
||||
string $outputDirectory,
|
||||
string $buildRuntime,
|
||||
string $adapter,
|
||||
@@ -118,9 +109,7 @@ class Create extends Base
|
||||
string $providerBranch,
|
||||
bool $providerSilentMode,
|
||||
string $providerRootDirectory,
|
||||
string $buildSpecification,
|
||||
string $runtimeSpecification,
|
||||
int $deploymentRetention,
|
||||
string $specification,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Document $project,
|
||||
@@ -155,13 +144,13 @@ class Create extends Base
|
||||
'logging' => $logging,
|
||||
'name' => $name,
|
||||
'framework' => $framework,
|
||||
'deploymentRetention' => $deploymentRetention,
|
||||
'deploymentInternalId' => '',
|
||||
'deploymentId' => '',
|
||||
'timeout' => $timeout,
|
||||
'installCommand' => $installCommand,
|
||||
'buildCommand' => $buildCommand,
|
||||
'startCommand' => $startCommand,
|
||||
'deploymentRetention' => 0,
|
||||
'startCommand' => '',
|
||||
'outputDirectory' => $outputDirectory,
|
||||
'search' => implode(' ', [$siteId, $name, $framework]),
|
||||
'fallbackFile' => $fallbackFile,
|
||||
@@ -173,8 +162,9 @@ class Create extends Base
|
||||
'providerBranch' => $providerBranch,
|
||||
'providerRootDirectory' => $providerRootDirectory,
|
||||
'providerSilentMode' => $providerSilentMode,
|
||||
'buildSpecification' => $buildSpecification,
|
||||
'runtimeSpecification' => $runtimeSpecification,
|
||||
'specification' => $specification,
|
||||
'buildSpecification' => $specification,
|
||||
'runtimeSpecification' => $specification,
|
||||
'buildRuntime' => $buildRuntime,
|
||||
'adapter' => $adapter,
|
||||
]);
|
||||
|
||||
@@ -71,7 +71,6 @@ class Update extends Base
|
||||
->param('timeout', 30, new Range(1, (int) System::getEnv('_APP_SITES_TIMEOUT', 30)), 'Maximum request time in seconds.', true)
|
||||
->param('installCommand', '', new Text(8192, 0), 'Install Command.', true)
|
||||
->param('buildCommand', '', new Text(8192, 0), 'Build Command.', true)
|
||||
->param('startCommand', '', new Text(8192, 0), 'Custom start command. Leave empty to use default.', true)
|
||||
->param('outputDirectory', '', new Text(8192, 0), 'Output Directory for site.', true)
|
||||
->param('buildRuntime', '', new WhiteList(array_keys(Config::getParam('runtimes')), true), 'Runtime to use during build step.', true)
|
||||
->param('adapter', '', new WhiteList(['static', 'ssr']), 'Framework adapter defining rendering strategy. Allowed values are: static, ssr', true)
|
||||
@@ -81,19 +80,12 @@ class Update extends Base
|
||||
->param('providerBranch', '', new Text(128, 0), 'Production branch for the repo linked to the site.', true)
|
||||
->param('providerSilentMode', false, new Boolean(), 'Is the VCS (Version Control System) connection in silent mode for the repo linked to the site? In silent mode, comments will not be made on commits and pull requests.', true)
|
||||
->param('providerRootDirectory', '', new Text(128, 0), 'Path to site code in the linked repo.', true)
|
||||
->param('buildSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
->param('specification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
$plan,
|
||||
Config::getParam('specifications', []),
|
||||
System::getEnv('_APP_COMPUTE_CPUS', 0),
|
||||
System::getEnv('_APP_COMPUTE_MEMORY', 0)
|
||||
), 'Build specification for the site deployments.', true, ['plan'])
|
||||
->param('runtimeSpecification', fn (array $plan) => $this->getDefaultSpecification($plan), fn (array $plan) => new Specification(
|
||||
$plan,
|
||||
Config::getParam('specifications', []),
|
||||
System::getEnv('_APP_COMPUTE_CPUS', 0),
|
||||
System::getEnv('_APP_COMPUTE_MEMORY', 0)
|
||||
), 'Runtime specification for the SSR executions.', true, ['plan'])
|
||||
->param('deploymentRetention', 0, new Range(0, APP_COMPUTE_DEPLOYMENT_MAX_RETENTION), 'Days to keep non-active deployments before deletion. Value 0 means all deployments will be kept.', true)
|
||||
), 'Framework specification for the site and builds.', true, ['plan'])
|
||||
->inject('request')
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
@@ -115,7 +107,6 @@ class Update extends Base
|
||||
int $timeout,
|
||||
string $installCommand,
|
||||
string $buildCommand,
|
||||
string $startCommand,
|
||||
string $outputDirectory,
|
||||
string $buildRuntime,
|
||||
string $adapter,
|
||||
@@ -125,9 +116,7 @@ class Update extends Base
|
||||
string $providerBranch,
|
||||
bool $providerSilentMode,
|
||||
string $providerRootDirectory,
|
||||
string $buildSpecification,
|
||||
string $runtimeSpecification,
|
||||
int $deploymentRetention,
|
||||
string $specification,
|
||||
Request $request,
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
@@ -227,7 +216,6 @@ class Update extends Base
|
||||
$site->getAttribute('name') !== $name ||
|
||||
$site->getAttribute('buildCommand') !== $buildCommand ||
|
||||
$site->getAttribute('installCommand') !== $installCommand ||
|
||||
$site->getAttribute('startCommand') !== $startCommand ||
|
||||
$site->getAttribute('outputDirectory') !== $outputDirectory ||
|
||||
$site->getAttribute('providerRootDirectory') !== $providerRootDirectory ||
|
||||
$site->getAttribute('framework') !== $framework
|
||||
@@ -235,24 +223,14 @@ class Update extends Base
|
||||
$live = false;
|
||||
}
|
||||
|
||||
if (!empty($site->getAttribute('deploymentId'))) {
|
||||
$specsChanged = false;
|
||||
// TODO: backwards-compatibility dual-read, remove eventually.
|
||||
if ($site->getAttribute('runtimeSpecification', $site->getAttribute('specification')) !== $runtimeSpecification) {
|
||||
$specsChanged = true;
|
||||
// TODO: backwards-compatibility dual-read, remove eventually.
|
||||
} elseif ($site->getAttribute('buildSpecification', $site->getAttribute('specification')) !== $buildSpecification) {
|
||||
$specsChanged = true;
|
||||
}
|
||||
|
||||
if ($specsChanged) {
|
||||
try {
|
||||
$executor->deleteRuntime($project->getId(), $site->getAttribute('deploymentId'));
|
||||
} catch (\Throwable $th) {
|
||||
// Don't throw if the deployment doesn't exist
|
||||
if ($th->getCode() !== 404) {
|
||||
throw $th;
|
||||
}
|
||||
// Enforce Cold Start if spec limits change.
|
||||
if ($site->getAttribute('specification') !== $specification && !empty($site->getAttribute('deploymentId'))) {
|
||||
try {
|
||||
$executor->deleteRuntime($project->getId(), $site->getAttribute('deploymentId'));
|
||||
} catch (\Throwable $th) {
|
||||
// Don't throw if the deployment doesn't exist
|
||||
if ($th->getCode() !== 404) {
|
||||
throw $th;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,10 +242,10 @@ class Update extends Base
|
||||
'logging' => $logging,
|
||||
'live' => $live,
|
||||
'timeout' => $timeout,
|
||||
'deploymentRetention' => $deploymentRetention,
|
||||
'installCommand' => $installCommand,
|
||||
'buildCommand' => $buildCommand,
|
||||
'startCommand' => $startCommand,
|
||||
'deploymentRetention' => 0,
|
||||
'startCommand' => '',
|
||||
'outputDirectory' => $outputDirectory,
|
||||
'installationId' => $installation->getId(),
|
||||
'installationInternalId' => $installation->getSequence(),
|
||||
@@ -277,8 +255,9 @@ class Update extends Base
|
||||
'providerBranch' => $providerBranch,
|
||||
'providerRootDirectory' => $providerRootDirectory,
|
||||
'providerSilentMode' => $providerSilentMode,
|
||||
'buildSpecification' => $buildSpecification,
|
||||
'runtimeSpecification' => $runtimeSpecification,
|
||||
'specification' => $specification,
|
||||
'buildSpecification' => $specification,
|
||||
'runtimeSpecification' => $specification,
|
||||
'search' => implode(' ', [$siteId, $name, $framework]),
|
||||
'buildRuntime' => $buildRuntime,
|
||||
'adapter' => $adapter,
|
||||
|
||||
@@ -13,7 +13,6 @@ use Utopia\Database\Document;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Platform\Action;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\WhiteList;
|
||||
|
||||
class Maintenance extends Action
|
||||
{
|
||||
@@ -26,7 +25,6 @@ class Maintenance extends Action
|
||||
{
|
||||
$this
|
||||
->desc('Schedules maintenance tasks and publishes them to our queues')
|
||||
->param('type', 'loop', new WhiteList(['loop', 'trigger']), 'How to run task. "loop" is meant for container entrypoint, and "trigger" for manual execution.')
|
||||
->inject('dbForPlatform')
|
||||
->inject('console')
|
||||
->inject('queueForCertificates')
|
||||
@@ -34,7 +32,7 @@ class Maintenance extends Action
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(string $type, Database $dbForPlatform, Document $console, Certificate $queueForCertificates, Delete $queueForDeletes): void
|
||||
public function action(Database $dbForPlatform, Document $console, Certificate $queueForCertificates, Delete $queueForDeletes): void
|
||||
{
|
||||
Console::title('Maintenance V1');
|
||||
Console::success(APP_NAME . ' maintenance process v1 has started');
|
||||
@@ -59,7 +57,9 @@ class Maintenance extends Action
|
||||
$delay = $next->getTimestamp() - $now->getTimestamp();
|
||||
}
|
||||
|
||||
$action = function () use ($interval, $cacheRetention, $schedulesDeletionRetention, $usageStatsRetentionHourly, $dbForPlatform, $console, $queueForDeletes, $queueForCertificates) {
|
||||
Console::info('Setting loop start time to ' . $next->format("Y-m-d H:i:s.v") . '. Delaying for ' . $delay . ' seconds.');
|
||||
|
||||
Console::loop(function () use ($interval, $cacheRetention, $schedulesDeletionRetention, $usageStatsRetentionHourly, $dbForPlatform, $console, $queueForDeletes, $queueForCertificates) {
|
||||
$time = DatabaseDateTime::now();
|
||||
|
||||
Console::info("[{$time}] Notifying workers with maintenance tasks every {$interval} seconds");
|
||||
@@ -96,17 +96,7 @@ class Maintenance extends Action
|
||||
$this->notifyDeleteCache($cacheRetention, $queueForDeletes);
|
||||
$this->notifyDeleteSchedules($schedulesDeletionRetention, $queueForDeletes);
|
||||
$this->notifyDeleteCSVExports($queueForDeletes);
|
||||
};
|
||||
|
||||
if ($type === 'loop') {
|
||||
Console::info('Setting loop start time to ' . $next->format("Y-m-d H:i:s.v") . '. Delaying for ' . $delay . ' seconds.');
|
||||
|
||||
Console::loop(function () use ($action) {
|
||||
$action();
|
||||
}, $interval, $delay);
|
||||
} elseif ($type === 'trigger') {
|
||||
$action();
|
||||
}
|
||||
}, $interval, $delay);
|
||||
}
|
||||
|
||||
private function notifyDeleteConnections(Delete $queueForDeletes): void
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace Appwrite\Platform\Workers;
|
||||
use Appwrite\Certificates\Adapter as CertificatesAdapter;
|
||||
use Appwrite\Deletes\Identities;
|
||||
use Appwrite\Deletes\Targets;
|
||||
use Appwrite\Event\Delete as DeleteEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Executor\Executor;
|
||||
use Throwable;
|
||||
@@ -66,7 +65,6 @@ class Deletes extends Action
|
||||
->inject('executionsRetentionCount')
|
||||
->inject('auditRetention')
|
||||
->inject('log')
|
||||
->inject('queueForDeletes')
|
||||
->inject('getAudit')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
@@ -92,7 +90,6 @@ class Deletes extends Action
|
||||
int $executionsRetentionCount,
|
||||
string $auditRetention,
|
||||
Log $log,
|
||||
DeleteEvent $queueForDeletes,
|
||||
callable $getAudit,
|
||||
): void {
|
||||
$payload = $message->getPayload() ?? [];
|
||||
@@ -213,7 +210,6 @@ class Deletes extends Action
|
||||
$this->deleteUsageStats($project, $getProjectDB, $getLogsDB, $hourlyUsageRetentionDatetime);
|
||||
$this->deleteExpiredSessions($project, $getProjectDB);
|
||||
$this->deleteExpiredTransactions($project, $getProjectDB);
|
||||
$this->deleteOldDeployments($queueForDeletes, $project, $getProjectDB);
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('No delete operation for type: ' . \strval($type));
|
||||
@@ -331,61 +327,6 @@ class Deletes extends Action
|
||||
Targets::delete($getProjectDB($project), Query::equal('sessionInternalId', [$session->getSequence()]));
|
||||
}
|
||||
|
||||
private function deleteOldDeployments(DeleteEvent $queueForDeletes, Document $project, callable $getProjectDB): void
|
||||
{
|
||||
/** @var Database $dbForProject */
|
||||
$dbForProject = $getProjectDB($project);
|
||||
|
||||
$removalCallback = function (Document $resource) use ($dbForProject, $queueForDeletes, $project) {
|
||||
$retention = $resource->getAttribute('deploymentRetention', 0);
|
||||
|
||||
// 0 means unlimited - never delete
|
||||
if ($retention === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$activeDeploymentId = $resource->getAttribute('deploymentId', '');
|
||||
|
||||
$queries = [
|
||||
Query::createdBefore(DateTime::addSeconds(new \DateTime(), -1 * $retention * 24 * 60 * 60)),
|
||||
Query::equal('resourceInternalId', [$resource->getSequence()]),
|
||||
Query::equal('resourceType', [$resource->getCollection()]),
|
||||
Query::orderDesc('$createdAt'),
|
||||
];
|
||||
|
||||
if (!empty($activeDeploymentId)) {
|
||||
$queries[] = Query::notEqual('$id', $activeDeploymentId);
|
||||
}
|
||||
|
||||
$this->deleteByGroup(
|
||||
'deployments',
|
||||
$queries,
|
||||
$dbForProject,
|
||||
function (Document $deployment) use ($queueForDeletes, $project) {
|
||||
$queueForDeletes
|
||||
->setType(DELETE_TYPE_DOCUMENT)
|
||||
->setDocument($deployment)
|
||||
->setProject($project)
|
||||
->trigger();
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$this->listByGroup(
|
||||
'functions',
|
||||
[],
|
||||
$dbForProject,
|
||||
$removalCallback
|
||||
);
|
||||
|
||||
$this->listByGroup(
|
||||
'sites',
|
||||
[],
|
||||
$dbForProject,
|
||||
$removalCallback
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Document $project
|
||||
* @param callable $getProjectDB
|
||||
|
||||
@@ -357,8 +357,7 @@ class Functions extends Action
|
||||
$user ??= new Document();
|
||||
$functionId = $function->getId();
|
||||
$deploymentId = $function->getAttribute('deploymentId', '');
|
||||
// TODO: backwards-compatibility dual-read, remove eventually.
|
||||
$spec = Config::getParam('specifications')[$function->getAttribute('runtimeSpecification', $function->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT))];
|
||||
$spec = Config::getParam('specifications')[$function->getAttribute('specification', APP_COMPUTE_SPECIFICATION_DEFAULT)];
|
||||
|
||||
$log->addTag('deploymentId', $deploymentId);
|
||||
|
||||
@@ -512,11 +511,6 @@ class Functions extends Action
|
||||
try {
|
||||
$version = $function->getAttribute('version', 'v2');
|
||||
$command = $runtime['startCommand'];
|
||||
|
||||
if (!empty($deployment->getAttribute('startCommand', ''))) {
|
||||
$command = 'cd /usr/local/server/src/function/ && ' . $deployment->getAttribute('startCommand', '');
|
||||
}
|
||||
|
||||
$source = $deployment->getAttribute('buildPath', '');
|
||||
$extension = str_ends_with($source, '.tar') ? 'tar' : 'tar.gz';
|
||||
$command = $version === 'v2' ? '' : "cp /tmp/code.$extension /mnt/code/code.$extension && nohup helpers/start.sh \"$command\"";
|
||||
|
||||
@@ -6,7 +6,7 @@ use Appwrite\Utopia\Request\Filter;
|
||||
|
||||
class V21 extends Filter
|
||||
{
|
||||
// Convert 1.8.0 params to 1.9.0
|
||||
// Convert 1.8.0 params to 1.8.1
|
||||
public function parse(array $content, string $model): array
|
||||
{
|
||||
switch ($model) {
|
||||
@@ -14,12 +14,6 @@ class V21 extends Filter
|
||||
case 'sites.createTemplateDeployment':
|
||||
$content = $this->convertVersionToTypeAndReference($content);
|
||||
break;
|
||||
case 'functions.create':
|
||||
case 'sites.create':
|
||||
case 'functions.update':
|
||||
case 'sites.update':
|
||||
$content = $this->convertSpecs($content);
|
||||
break;
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
@@ -37,15 +31,4 @@ class V21 extends Filter
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function convertSpecs(array $content): array
|
||||
{
|
||||
if (!empty($content['specification'])) {
|
||||
$content['buildSpecification'] = $content['specification'];
|
||||
$content['runtimeSpecification'] = $content['specification'];
|
||||
unset($content['specification']);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Filters;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Filter;
|
||||
|
||||
// Convert 1.9 Data format to 1.8 format
|
||||
class V21 extends Filter
|
||||
{
|
||||
public function parse(array $content, string $model): array
|
||||
{
|
||||
$parsedResponse = $content;
|
||||
|
||||
return match ($model) {
|
||||
Response::MODEL_SITE => $this->parseSite($content),
|
||||
Response::MODEL_SITE_LIST => $this->handleList(
|
||||
$content,
|
||||
"sites",
|
||||
fn ($item) => $this->parseSite($item),
|
||||
),
|
||||
Response::MODEL_FUNCTION => $this->parseFunction($content),
|
||||
Response::MODEL_FUNCTION_LIST => $this->handleList(
|
||||
$content,
|
||||
"functions",
|
||||
fn ($item) => $this->parseFunction($item),
|
||||
),
|
||||
default => $parsedResponse,
|
||||
};
|
||||
}
|
||||
|
||||
protected function parseSite(array $content): array
|
||||
{
|
||||
$content = $this->parseSpecs($content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function parseFunction(array $content): array
|
||||
{
|
||||
$content = $this->parseSpecs($content);
|
||||
return $content;
|
||||
}
|
||||
|
||||
protected function parseSpecs(array $content): array
|
||||
{
|
||||
$content['specification'] = $content['buildSpecification'] ?? null;
|
||||
unset($content['buildSpecification']);
|
||||
unset($content['runtimeSpecification']);
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
@@ -65,12 +65,6 @@ class Func extends Model
|
||||
'default' => '',
|
||||
'example' => 'python-3.8',
|
||||
])
|
||||
->addRule('deploymentRetention', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'How many days to keep the non-active deployments before they will be automatically deleted.',
|
||||
'default' => 0,
|
||||
'example' => 7,
|
||||
])
|
||||
->addRule('deploymentId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function\'s active deployment ID.',
|
||||
@@ -182,15 +176,9 @@ class Func extends Model
|
||||
'default' => false,
|
||||
'example' => false,
|
||||
])
|
||||
->addRule('buildSpecification', [
|
||||
->addRule('specification', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Machine specification for deployment builds.',
|
||||
'default' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
'example' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
])
|
||||
->addRule('runtimeSpecification', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Machine specification for executions.',
|
||||
'description' => 'Machine specification for builds and executions.',
|
||||
'default' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
'example' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
])
|
||||
|
||||
@@ -58,12 +58,6 @@ class Site extends Model
|
||||
'default' => '',
|
||||
'example' => 'react',
|
||||
])
|
||||
->addRule('deploymentRetention', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'How many days to keep the non-active deployments before they will be automatically deleted.',
|
||||
'default' => 0,
|
||||
'example' => 7,
|
||||
])
|
||||
->addRule('deploymentId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Site\'s active deployment ID.',
|
||||
@@ -131,12 +125,6 @@ class Site extends Model
|
||||
'default' => '',
|
||||
'example' => 'npm run build',
|
||||
])
|
||||
->addRule('startCommand', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Custom command to use when starting site runtime.',
|
||||
'default' => '',
|
||||
'example' => 'node custom-server.mjs',
|
||||
])
|
||||
->addRule('outputDirectory', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The directory where the site build output is located.',
|
||||
@@ -173,15 +161,9 @@ class Site extends Model
|
||||
'default' => false,
|
||||
'example' => false,
|
||||
])
|
||||
->addRule('buildSpecification', [
|
||||
->addRule('specification', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Machine specification for deployment builds.',
|
||||
'default' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
'example' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
])
|
||||
->addRule('runtimeSpecification', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Machine specification for SSR executions.',
|
||||
'description' => 'Machine specification for builds and executions.',
|
||||
'default' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
'example' => APP_COMPUTE_SPECIFICATION_DEFAULT,
|
||||
])
|
||||
|
||||
@@ -958,8 +958,7 @@ class UsageTest extends Scope
|
||||
],
|
||||
'schedule' => '0 0 1 1 *',
|
||||
'timeout' => 10,
|
||||
'buildSpecification' => Specification::S_8VCPU_8GB,
|
||||
'runtimeSpecification' => Specification::S_4VCPU_4GB,
|
||||
'specification' => Specification::S_8VCPU_8GB
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideConsole;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
use Utopia\Database\Helpers\Role;
|
||||
|
||||
@@ -654,58 +653,4 @@ class FunctionsConsoleClientTest extends Scope
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testFunctionDeploymentRetentionWithMaintenance(): void
|
||||
{
|
||||
$functionId = $this->setupFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test retention function',
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'deploymentRetention' => 180
|
||||
]);
|
||||
$this->assertNotEmpty($functionId);
|
||||
|
||||
$deploymentIdInactive = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentIdInactive);
|
||||
|
||||
$deploymentIdInactiveOld = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentIdInactiveOld);
|
||||
|
||||
$deploymentIdActive = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('node'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentIdActive);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/mock/time-travels', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'projectId' => $this->getProject()['$id'],
|
||||
'resourceType' => 'deployment',
|
||||
'resourceId' => $deploymentIdInactiveOld,
|
||||
'createdAt' => '2020-01-01T00:00:00Z' // More than 180 days ago
|
||||
]);
|
||||
$this->assertSame(204, $response['headers']['status-code']);
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
$code = Console::execute("docker exec appwrite-task-maintenance maintenance --type=trigger", '', $stdout, $stderr);
|
||||
$this->assertSame(0, $code, "Maintenance command failed with code $code: $stderr ($stdout)");
|
||||
|
||||
$this->assertEventually(function () use ($functionId) {
|
||||
$response = $this->listDeployments($functionId);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(2, $response['body']['total']);
|
||||
});
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,17 +207,14 @@ class FunctionsCustomServerTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Specs function',
|
||||
'runtime' => 'node-22',
|
||||
'buildSpecification' => $specifications['body']['specifications'][0]['slug'],
|
||||
'runtimeSpecification' => $specifications['body']['specifications'][1]['slug'],
|
||||
'specification' => $specifications['body']['specifications'][0]['slug']
|
||||
]);
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
$this->assertEquals($specifications['body']['specifications'][0]['slug'], $function['body']['buildSpecification']);
|
||||
$this->assertEquals($specifications['body']['specifications'][1]['slug'], $function['body']['runtimeSpecification']);
|
||||
$this->assertEquals($specifications['body']['specifications'][0]['slug'], $function['body']['specification']);
|
||||
|
||||
$function = $this->getFunction($function['body']['$id']);
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertEquals($specifications['body']['specifications'][0]['slug'], $function['body']['buildSpecification']);
|
||||
$this->assertEquals($specifications['body']['specifications'][1]['slug'], $function['body']['runtimeSpecification']);
|
||||
$this->assertEquals($specifications['body']['specifications'][0]['slug'], $function['body']['specification']);
|
||||
|
||||
$this->cleanupFunction($function['body']['$id']);
|
||||
|
||||
@@ -225,15 +222,7 @@ class FunctionsCustomServerTest extends Scope
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Specs function',
|
||||
'runtime' => 'node-22',
|
||||
'buildSpecification' => 'cheap-please'
|
||||
]);
|
||||
$this->assertEquals(400, $function['headers']['status-code']);
|
||||
|
||||
$function = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Specs function',
|
||||
'runtime' => 'node-22',
|
||||
'runtimeSpecification' => 'cheap-please'
|
||||
'specification' => 'cheap-please'
|
||||
]);
|
||||
$this->assertEquals(400, $function['headers']['status-code']);
|
||||
}
|
||||
@@ -1563,12 +1552,12 @@ class FunctionsCustomServerTest extends Scope
|
||||
'timeout' => 15,
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'runtimeSpecification' => Specification::S_1VCPU_1GB,
|
||||
'specification' => Specification::S_1VCPU_1GB,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
$this->assertEquals(Specification::S_1VCPU_1GB, $function['body']['runtimeSpecification']);
|
||||
$this->assertEquals(Specification::S_1VCPU_1GB, $function['body']['specification']);
|
||||
|
||||
// Verify the updated specs
|
||||
$execution = $this->createExecution($functionId);
|
||||
@@ -1597,12 +1586,12 @@ class FunctionsCustomServerTest extends Scope
|
||||
'timeout' => 15,
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'runtimeSpecification' => Specification::S_1VCPU_512MB,
|
||||
'specification' => Specification::S_1VCPU_512MB,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
$this->assertEquals(Specification::S_1VCPU_512MB, $function['body']['runtimeSpecification']);
|
||||
$this->assertEquals(Specification::S_1VCPU_512MB, $function['body']['specification']);
|
||||
|
||||
// Verify the updated specs
|
||||
$execution = $this->createExecution($functionId);
|
||||
@@ -1627,31 +1616,11 @@ class FunctionsCustomServerTest extends Scope
|
||||
'timeout' => 15,
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'buildSpecification' => 's-2vcpu-512mb', // Invalid specification
|
||||
'specification' => 's-2vcpu-512mb', // Invalid specification
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $function['headers']['status-code']);
|
||||
$this->assertStringStartsWith('Invalid `buildSpecification` param: Specification must be one of:', $function['body']['message']);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_PUT, '/functions/' . $data['functionId'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'name' => 'Test1',
|
||||
'events' => [
|
||||
'users.*.update.name',
|
||||
'users.*.update.email',
|
||||
],
|
||||
'timeout' => 15,
|
||||
'runtime' => 'node-22',
|
||||
'entrypoint' => 'index.js',
|
||||
'runtimeSpecification' => 's-2vcpu-512mb', // Invalid specification
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $function['headers']['status-code']);
|
||||
$this->assertStringStartsWith('Invalid `runtimeSpecification` param: Specification must be one of:', $function['body']['message']);
|
||||
|
||||
return $data;
|
||||
$this->assertStringStartsWith('Invalid `specification` param: Specification must be one of:', $function['body']['message']);
|
||||
}
|
||||
|
||||
public function testDeleteDeployment(): void
|
||||
@@ -2252,8 +2221,6 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
$this->assertArrayNotHasKey('scopes', $response['body']);
|
||||
$this->assertArrayNotHasKey('specification', $response['body']);
|
||||
$this->assertArrayNotHasKey('buildSpecification', $response['body']);
|
||||
$this->assertArrayNotHasKey('runtimeSpecification', $response['body']);
|
||||
|
||||
// get function with 1.5.0 response format header
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $response['body']['$id'], array_merge([
|
||||
@@ -2264,31 +2231,13 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertArrayNotHasKey('scopes', $function['body']);
|
||||
$this->assertArrayNotHasKey('buildSpecification', $function['body']);
|
||||
$this->assertArrayNotHasKey('runtimeSpecification', $function['body']);
|
||||
$this->assertArrayNotHasKey('specification', $function['body']);
|
||||
|
||||
// get function with 1.8.0 response format header
|
||||
$function = $this->client->call(Client::METHOD_GET, '/functions/' . $response['body']['$id'], array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-response-format' => '1.8.0', // add response format header
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertArrayHasKey('scopes', $function['body']);
|
||||
$this->assertArrayHasKey('specification', $function['body']);
|
||||
$this->assertArrayNotHasKey('buildSpecification', $function['body']);
|
||||
$this->assertArrayNotHasKey('runtimeSpecification', $function['body']);
|
||||
|
||||
// get function with latest version
|
||||
$function = $this->getFunction($function['body']['$id']);
|
||||
|
||||
$this->assertEquals(200, $function['headers']['status-code']);
|
||||
$this->assertArrayHasKey('scopes', $function['body']);
|
||||
$this->assertArrayNotHasKey('specification', $function['body']);
|
||||
$this->assertArrayHasKey('buildSpecification', $function['body']);
|
||||
$this->assertArrayHasKey('runtimeSpecification', $function['body']);
|
||||
$this->assertArrayHasKey('specification', $function['body']);
|
||||
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
$this->cleanupFunction($functionId);
|
||||
@@ -2438,17 +2387,15 @@ class FunctionsCustomServerTest extends Scope
|
||||
'entrypoint' => 'index.js',
|
||||
'logging' => false,
|
||||
'execute' => ['any'],
|
||||
'buildSpecification' => Specification::S_2VCPU_2GB,
|
||||
'runtimeSpecification' => Specification::S_1VCPU_1GB,
|
||||
'specification' => Specification::S_2VCPU_2GB,
|
||||
'commands' => 'echo $APPWRITE_FUNCTION_MEMORY:$APPWRITE_FUNCTION_CPUS',
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $function['headers']['status-code']);
|
||||
$this->assertEquals(Specification::S_2VCPU_2GB, $function['body']['buildSpecification']);
|
||||
$this->assertEquals(Specification::S_1VCPU_1GB, $function['body']['runtimeSpecification']);
|
||||
$this->assertEquals(Specification::S_2VCPU_2GB, $function['body']['specification']);
|
||||
$this->assertNotEmpty($function['body']['$id']);
|
||||
|
||||
$functionId = $function['body']['$id'] ?? '';
|
||||
$functionId = $functionId = $function['body']['$id'] ?? '';
|
||||
|
||||
$deploymentId = $this->setupDeployment($functionId, [
|
||||
'code' => $this->packageFunction('basic'),
|
||||
@@ -2467,8 +2414,8 @@ class FunctionsCustomServerTest extends Scope
|
||||
$this->assertNotEmpty($execution['body']['$id']);
|
||||
|
||||
$executionResponse = json_decode($execution['body']['responseBody'], true);
|
||||
$this->assertEquals('1024', $executionResponse['APPWRITE_FUNCTION_MEMORY']);
|
||||
$this->assertEquals('1', $executionResponse['APPWRITE_FUNCTION_CPUS']);
|
||||
$this->assertEquals('2048', $executionResponse['APPWRITE_FUNCTION_MEMORY']);
|
||||
$this->assertEquals('2', $executionResponse['APPWRITE_FUNCTION_CPUS']);
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
@@ -2837,119 +2784,4 @@ class FunctionsCustomServerTest extends Scope
|
||||
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
|
||||
public function testFunctionDeploymentRetention(): void
|
||||
{
|
||||
$functionIds = [];
|
||||
|
||||
// Default
|
||||
$response = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test retention function',
|
||||
'runtime' => 'node-22',
|
||||
]);
|
||||
$this->assertSame(201, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
$functionIds[] = $response['body']['$id'];
|
||||
|
||||
$response = $this->getFunction($response['body']['$id']);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
|
||||
// Success values
|
||||
$response = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test retention function',
|
||||
'runtime' => 'node-22',
|
||||
'deploymentRetention' => 0
|
||||
]);
|
||||
$this->assertSame(201, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
$functionIds[] = $response['body']['$id'];
|
||||
|
||||
$response = $this->getFunction($response['body']['$id']);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
|
||||
$response = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test retention function',
|
||||
'runtime' => 'node-22',
|
||||
'deploymentRetention' => 180
|
||||
]);
|
||||
$this->assertSame(201, $response['headers']['status-code']);
|
||||
$this->assertSame(180, $response['body']['deploymentRetention']);
|
||||
$functionIds[] = $response['body']['$id'];
|
||||
|
||||
$response = $this->getFunction($response['body']['$id']);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(180, $response['body']['deploymentRetention']);
|
||||
|
||||
// Failure values
|
||||
$response = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test retention function',
|
||||
'runtime' => 'node-22',
|
||||
'deploymentRetention' => 999999
|
||||
]);
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test retention function',
|
||||
'runtime' => 'node-22',
|
||||
'deploymentRetention' => -1
|
||||
]);
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
|
||||
// Update flow
|
||||
$response = $this->createFunction([
|
||||
'functionId' => ID::unique(),
|
||||
'name' => 'Test retention function',
|
||||
'runtime' => 'node-22',
|
||||
'deploymentRetention' => 180
|
||||
]);
|
||||
$this->assertSame(201, $response['headers']['status-code']);
|
||||
$this->assertSame(180, $response['body']['deploymentRetention']);
|
||||
$functionIds[] = $response['body']['$id'];
|
||||
$functionIdForUpdate = $response['body']['$id'];
|
||||
|
||||
$response = $this->updateFunction($functionIdForUpdate, [
|
||||
'name' => 'Test retention function',
|
||||
'deploymentRetention' => 90
|
||||
]);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(90, $response['body']['deploymentRetention']);
|
||||
|
||||
$response = $this->getFunction($functionIdForUpdate);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(90, $response['body']['deploymentRetention']);
|
||||
|
||||
$response = $this->updateFunction($functionIdForUpdate, [
|
||||
'name' => 'Test retention function',
|
||||
]);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
|
||||
$response = $this->getFunction($functionIdForUpdate);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
|
||||
// Failed update flow
|
||||
$response = $this->updateFunction($functionIdForUpdate, [
|
||||
'name' => 'Test retention function',
|
||||
'deploymentRetention' => -1
|
||||
]);
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->updateFunction($functionIdForUpdate, [
|
||||
'name' => 'Test retention function',
|
||||
'deploymentRetention' => 999999
|
||||
]);
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
|
||||
foreach ($functionIds as $functionId) {
|
||||
$this->cleanupFunction($functionId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ use Tests\E2E\Client;
|
||||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideConsole;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
|
||||
class SitesConsoleClientTest extends Scope
|
||||
@@ -148,58 +147,4 @@ class SitesConsoleClientTest extends Scope
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
|
||||
public function testSiteDeploymentRetentionWithMaintenance(): void
|
||||
{
|
||||
$siteId = $this->setupSite([
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'deploymentRetention' => 180,
|
||||
'buildRuntime' => 'node-22',
|
||||
]);
|
||||
$this->assertNotEmpty($siteId);
|
||||
|
||||
$deploymentIdInactive = $this->setupDeployment($siteId, [
|
||||
'code' => $this->packageSite('static'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentIdInactive);
|
||||
|
||||
$deploymentIdInactiveOld = $this->setupDeployment($siteId, [
|
||||
'code' => $this->packageSite('static'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentIdInactiveOld);
|
||||
|
||||
$deploymentIdActive = $this->setupDeployment($siteId, [
|
||||
'code' => $this->packageSite('static'),
|
||||
'activate' => true
|
||||
]);
|
||||
$this->assertNotEmpty($deploymentIdActive);
|
||||
|
||||
$response = $this->client->call(Client::METHOD_POST, '/mock/time-travels', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'projectId' => $this->getProject()['$id'],
|
||||
'resourceType' => 'deployment',
|
||||
'resourceId' => $deploymentIdInactiveOld,
|
||||
'createdAt' => '2020-01-01T00:00:00Z' // More than 180 days ago
|
||||
]);
|
||||
$this->assertSame(204, $response['headers']['status-code']);
|
||||
|
||||
$stdout = '';
|
||||
$stderr = '';
|
||||
$code = Console::execute("docker exec appwrite-task-maintenance maintenance --type=trigger", '', $stdout, $stderr);
|
||||
$this->assertSame(0, $code, "Maintenance command failed with code $code: $stderr ($stdout)");
|
||||
|
||||
$this->assertEventually(function () use ($siteId) {
|
||||
$response = $this->listDeployments($siteId);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(2, $response['body']['total']);
|
||||
});
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,17 +38,14 @@ class SitesCustomServerTest extends Scope
|
||||
'framework' => 'other',
|
||||
'name' => 'Specs site',
|
||||
'siteId' => ID::unique(),
|
||||
'buildSpecification' => $specifications['body']['specifications'][0]['slug'],
|
||||
'runtimeSpecification' => $specifications['body']['specifications'][1]['slug'],
|
||||
'specification' => $specifications['body']['specifications'][0]['slug']
|
||||
]);
|
||||
$this->assertEquals(201, $site['headers']['status-code']);
|
||||
$this->assertEquals($specifications['body']['specifications'][0]['slug'], $site['body']['buildSpecification']);
|
||||
$this->assertEquals($specifications['body']['specifications'][1]['slug'], $site['body']['runtimeSpecification']);
|
||||
$this->assertEquals($specifications['body']['specifications'][0]['slug'], $site['body']['specification']);
|
||||
|
||||
$site = $this->getSite($site['body']['$id']);
|
||||
$this->assertEquals(200, $site['headers']['status-code']);
|
||||
$this->assertEquals($specifications['body']['specifications'][0]['slug'], $site['body']['buildSpecification']);
|
||||
$this->assertEquals($specifications['body']['specifications'][1]['slug'], $site['body']['runtimeSpecification']);
|
||||
$this->assertEquals($specifications['body']['specifications'][0]['slug'], $site['body']['specification']);
|
||||
|
||||
$this->cleanupSite($site['body']['$id']);
|
||||
|
||||
@@ -57,16 +54,7 @@ class SitesCustomServerTest extends Scope
|
||||
'framework' => 'other',
|
||||
'name' => 'Specs site',
|
||||
'siteId' => ID::unique(),
|
||||
'buildSpecification' => 'cheap-please'
|
||||
]);
|
||||
$this->assertEquals(400, $site['headers']['status-code']);
|
||||
|
||||
$site = $this->createSite([
|
||||
'buildRuntime' => 'node-22',
|
||||
'framework' => 'other',
|
||||
'name' => 'Specs site',
|
||||
'siteId' => ID::unique(),
|
||||
'runtimeSpecification' => 'cheap-please'
|
||||
'specification' => 'cheap-please'
|
||||
]);
|
||||
$this->assertEquals(400, $site['headers']['status-code']);
|
||||
}
|
||||
@@ -1304,12 +1292,12 @@ class SitesCustomServerTest extends Scope
|
||||
'providerBranch' => 'main',
|
||||
'providerRootDirectory' => './',
|
||||
'$id' => $siteId,
|
||||
'runtimeSpecification' => Specification::S_1VCPU_1GB,
|
||||
'specification' => Specification::S_1VCPU_1GB,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $site['headers']['status-code']);
|
||||
$this->assertNotEmpty($site['body']['$id']);
|
||||
$this->assertEquals(Specification::S_1VCPU_1GB, $site['body']['runtimeSpecification']);
|
||||
$this->assertEquals(Specification::S_1VCPU_1GB, $site['body']['specification']);
|
||||
|
||||
// Change the specs to 1vcpu 512mb
|
||||
$site = $this->updateSite([
|
||||
@@ -1321,12 +1309,12 @@ class SitesCustomServerTest extends Scope
|
||||
'providerBranch' => 'main',
|
||||
'providerRootDirectory' => './',
|
||||
'$id' => $siteId,
|
||||
'runtimeSpecification' => Specification::S_1VCPU_512MB,
|
||||
'specification' => Specification::S_1VCPU_512MB,
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $site['headers']['status-code']);
|
||||
$this->assertNotEmpty($site['body']['$id']);
|
||||
$this->assertEquals(Specification::S_1VCPU_512MB, $site['body']['runtimeSpecification']);
|
||||
$this->assertEquals(Specification::S_1VCPU_512MB, $site['body']['specification']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
@@ -1341,26 +1329,11 @@ class SitesCustomServerTest extends Scope
|
||||
'providerBranch' => 'main',
|
||||
'providerRootDirectory' => './',
|
||||
'$id' => $siteId,
|
||||
'buildSpecification' => 's-2vcpu-512mb', // Invalid specification
|
||||
'specification' => 's-2vcpu-512mb', // Invalid specification
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $site['headers']['status-code']);
|
||||
$this->assertStringStartsWith('Invalid `buildSpecification` param: Specification must be one of:', $site['body']['message']);
|
||||
|
||||
$site = $this->updateSite([
|
||||
'buildRuntime' => 'node-22',
|
||||
'fallbackFile' => '',
|
||||
'framework' => 'other',
|
||||
'name' => 'Test Site',
|
||||
'outputDirectory' => './',
|
||||
'providerBranch' => 'main',
|
||||
'providerRootDirectory' => './',
|
||||
'$id' => $siteId,
|
||||
'runtimeSpecification' => 's-2vcpu-512mb', // Invalid specification
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $site['headers']['status-code']);
|
||||
$this->assertStringStartsWith('Invalid `runtimeSpecification` param: Specification must be one of:', $site['body']['message']);
|
||||
$this->assertStringStartsWith('Invalid `specification` param: Specification must be one of:', $site['body']['message']);
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
@@ -3033,243 +3006,4 @@ class SitesCustomServerTest extends Scope
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
|
||||
public function testSiteCustomStartCommand(): void
|
||||
{
|
||||
$siteId = $this->setupSite([
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Astro site',
|
||||
'framework' => 'astro',
|
||||
'adapter' => 'ssr',
|
||||
'startCommand' => 'node custom-server.js',
|
||||
'buildRuntime' => 'node-22',
|
||||
'outputDirectory' => './dist',
|
||||
'buildCommand' => 'npm run build',
|
||||
'installCommand' => 'npm install',
|
||||
'fallbackFile' => '',
|
||||
]);
|
||||
|
||||
$this->assertNotEmpty($siteId);
|
||||
|
||||
$domain = $this->setupSiteDomain($siteId);
|
||||
|
||||
$deploymentId = $this->setupDeployment($siteId, [
|
||||
'code' => $this->packageSite('astro-custom-start-command'),
|
||||
'activate' => 'true'
|
||||
]);
|
||||
|
||||
$this->assertNotEmpty($deploymentId);
|
||||
|
||||
$domain = $this->getSiteDomain($siteId);
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("Homepage OK", $response['body']);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/ssr');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("SSR OK", $response['body']);
|
||||
$originalBody = $response['body'];
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/ssr');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("SSR OK", $response['body']);
|
||||
$this->assertNotEquals($originalBody, $response['body']); // Includes Date.now()
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/ssr-custom');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("Custom SSR OK", $response['body']);
|
||||
$originalBody = $response['body'];
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/ssr-custom');
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("Custom SSR OK", $response['body']);
|
||||
$this->assertNotEquals($originalBody, $response['body']); // Includes Date.now()
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/non-existing');
|
||||
$this->assertEquals(500, $response['headers']['status-code']);
|
||||
$this->assertStringContainsString("Custom error", $response['body']);
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
|
||||
public function testSiteSpecifications()
|
||||
{
|
||||
// Check if the site specifications are correctly set in builds
|
||||
$site = $this->createSite([
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Astro site',
|
||||
'framework' => 'astro',
|
||||
'adapter' => 'ssr',
|
||||
'buildRuntime' => 'node-22',
|
||||
'outputDirectory' => './dist',
|
||||
'buildCommand' => 'npm run build && echo $APPWRITE_SITE_MEMORY:$APPWRITE_SITE_CPUS',
|
||||
'installCommand' => 'npm install',
|
||||
'fallbackFile' => '',
|
||||
'buildSpecification' => Specification::S_2VCPU_2GB,
|
||||
'runtimeSpecification' => Specification::S_1VCPU_1GB,
|
||||
]);
|
||||
|
||||
$this->assertEquals(201, $site['headers']['status-code']);
|
||||
$this->assertEquals(Specification::S_2VCPU_2GB, $site['body']['buildSpecification']);
|
||||
$this->assertEquals(Specification::S_1VCPU_1GB, $site['body']['runtimeSpecification']);
|
||||
$this->assertNotEmpty($site['body']['$id']);
|
||||
|
||||
$siteId = $site['body']['$id'] ?? '';
|
||||
|
||||
$domain = $this->setupSiteDomain($siteId);
|
||||
|
||||
$deploymentId = $this->setupDeployment($siteId, [
|
||||
'code' => $this->packageSite('astro'),
|
||||
'activate' => true
|
||||
]);
|
||||
|
||||
$this->assertEventually(function () use ($siteId, $deploymentId) {
|
||||
$deployment = $this->getDeployment($siteId, $deploymentId);
|
||||
$this->assertStringContainsString('2048:2', $deployment['body']['buildLogs']);
|
||||
}, 10000, 500);
|
||||
|
||||
// Check if the sites specifications are correctly set in executions
|
||||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_GET, '/specs');
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertNotEmpty($response['body']);
|
||||
$this->assertEquals('1024', $response['body']['APPWRITE_SITE_MEMORY']);
|
||||
$this->assertEquals('1', $response['body']['APPWRITE_SITE_CPUS']);
|
||||
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
|
||||
public function testSiteDeploymentRetention(): void
|
||||
{
|
||||
$siteIds = [];
|
||||
|
||||
// Default
|
||||
$response = $this->createSite([
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'buildRuntime' => 'node-22',
|
||||
]);
|
||||
$this->assertSame(201, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
$siteIds[] = $response['body']['$id'];
|
||||
|
||||
$response = $this->getSite($response['body']['$id']);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
|
||||
// Success values
|
||||
$response = $this->createSite([
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'buildRuntime' => 'node-22',
|
||||
'deploymentRetention' => 0
|
||||
]);
|
||||
$this->assertSame(201, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
$siteIds[] = $response['body']['$id'];
|
||||
|
||||
$response = $this->getSite($response['body']['$id']);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
|
||||
$response = $this->createSite([
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'buildRuntime' => 'node-22',
|
||||
'deploymentRetention' => 180
|
||||
]);
|
||||
$this->assertSame(201, $response['headers']['status-code']);
|
||||
$this->assertSame(180, $response['body']['deploymentRetention']);
|
||||
$siteIds[] = $response['body']['$id'];
|
||||
|
||||
$response = $this->getSite($response['body']['$id']);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(180, $response['body']['deploymentRetention']);
|
||||
|
||||
// Failure values
|
||||
$response = $this->createSite([
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'buildRuntime' => 'node-22',
|
||||
'deploymentRetention' => 999999
|
||||
]);
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->createSite([
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'buildRuntime' => 'node-22',
|
||||
'deploymentRetention' => -1
|
||||
]);
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
|
||||
// Update flow
|
||||
$response = $this->createSite([
|
||||
'siteId' => ID::unique(),
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'buildRuntime' => 'node-22',
|
||||
'deploymentRetention' => 180
|
||||
]);
|
||||
$this->assertSame(201, $response['headers']['status-code']);
|
||||
$this->assertSame(180, $response['body']['deploymentRetention']);
|
||||
$siteIds[] = $response['body']['$id'];
|
||||
$siteIdToUpdate = $response['body']['$id'];
|
||||
|
||||
$response = $this->updateSite([
|
||||
'$id' => $siteIdToUpdate,
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'deploymentRetention' => 90
|
||||
]);
|
||||
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(90, $response['body']['deploymentRetention']);
|
||||
|
||||
$response = $this->getSite($siteIdToUpdate);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(90, $response['body']['deploymentRetention']);
|
||||
|
||||
$response = $this->updateSite([
|
||||
'$id' => $siteIdToUpdate,
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
]);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
|
||||
$response = $this->getSite($siteIdToUpdate);
|
||||
$this->assertSame(200, $response['headers']['status-code']);
|
||||
$this->assertSame(0, $response['body']['deploymentRetention']);
|
||||
|
||||
// Failed update flow
|
||||
$response = $this->updateSite([
|
||||
'$id' => $siteIdToUpdate,
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'deploymentRetention' => -1
|
||||
]);
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
|
||||
$response = $this->updateSite([
|
||||
'$id' => $siteIdToUpdate,
|
||||
'name' => 'Test retention site',
|
||||
'framework' => 'other',
|
||||
'deploymentRetention' => 999999
|
||||
]);
|
||||
$this->assertSame(400, $response['headers']['status-code']);
|
||||
|
||||
foreach ($siteIds as $siteId) {
|
||||
$this->cleanupSite($siteId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# build output
|
||||
dist/
|
||||
# generated types
|
||||
.astro/
|
||||
|
||||
# dependencies
|
||||
node_modules/
|
||||
|
||||
# logs
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
|
||||
|
||||
# environment variables
|
||||
.env
|
||||
.env.production
|
||||
|
||||
# macOS-specific files
|
||||
.DS_Store
|
||||
|
||||
# jetbrains setting folder
|
||||
.idea/
|
||||
@@ -1,10 +0,0 @@
|
||||
// @ts-check
|
||||
import { defineConfig } from 'astro/config';
|
||||
import node from '@astrojs/node';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
adapter: node({
|
||||
mode: 'middleware',
|
||||
}),
|
||||
});
|
||||
@@ -1,16 +0,0 @@
|
||||
import express from 'express';
|
||||
import { handler as ssrHandler } from './server/entry.mjs';
|
||||
|
||||
const app = express();
|
||||
const base = '/';
|
||||
app.use(base, express.static('client/'));
|
||||
app.get('/ssr-custom', (_req, res) => {
|
||||
res.send('Custom SSR OK (' + Date.now() + ')');
|
||||
});
|
||||
app.use(ssrHandler);
|
||||
|
||||
app.use((_req, res) => {
|
||||
res.status(500).send('Custom error');
|
||||
});
|
||||
|
||||
app.listen(3000);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "astro-custom-start-command",
|
||||
"type": "module",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"build": "astro build && cp custom-server.js dist/custom-server.js && rm -rf node_modules && npm install --production",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/node": "^9.5.1",
|
||||
"express": "^5.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"astro": "^5.16.6"
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
---
|
||||
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>Astro</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Homepage OK</h1>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +0,0 @@
|
||||
export const prerender = false;
|
||||
|
||||
export const GET = async () => {
|
||||
return new Response("SSR OK (" + Date.now() + ")");
|
||||
};
|
||||
@@ -1,13 +0,0 @@
|
||||
export async function GET(_context) {
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
APPWRITE_SITE_MEMORY: process.env.APPWRITE_SITE_MEMORY,
|
||||
APPWRITE_SITE_CPUS: process.env.APPWRITE_SITE_CPUS,
|
||||
}),
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user