Merge branch '1.6.x' into feat-development-keys
This commit is contained in:
commit
d7b19a8b52
35 changed files with 2715 additions and 358 deletions
68
.github/workflows/tests.yml
vendored
68
.github/workflows/tests.yml
vendored
|
@ -148,3 +148,71 @@ jobs:
|
|||
|
||||
- name: Run ${{matrix.service}} Shared Tables Tests
|
||||
run: _APP_DATABASE_SHARED_TABLES=database_db_main docker compose exec -T appwrite test /usr/src/code/tests/e2e/Services/${{matrix.service}} --debug
|
||||
|
||||
benchamrking:
|
||||
name: Benchmark
|
||||
runs-on: ubuntu-latest
|
||||
needs: setup
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: Load Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
key: ${{ env.CACHE_KEY }}
|
||||
path: /tmp/${{ env.IMAGE }}.tar
|
||||
fail-on-cache-miss: true
|
||||
- name: Load and Start Appwrite
|
||||
run: |
|
||||
sed -i 's/traefik/localhost/g' .env
|
||||
docker load --input /tmp/${{ env.IMAGE }}.tar
|
||||
docker compose up -d
|
||||
sleep 10
|
||||
- name: Install Oha
|
||||
run: |
|
||||
echo "deb [signed-by=/usr/share/keyrings/azlux-archive-keyring.gpg] http://packages.azlux.fr/debian/ stable main" | sudo tee /etc/apt/sources.list.d/azlux.list
|
||||
sudo wget -O /usr/share/keyrings/azlux-archive-keyring.gpg https://azlux.fr/repo.gpg
|
||||
sudo apt update
|
||||
sudo apt install oha
|
||||
- name: Benchmark PR
|
||||
run: oha -z 180s http://localhost/v1/health/version -j > benchmark.json
|
||||
- name: Cleaning
|
||||
run: docker compose down -v
|
||||
- name: Installing latest version
|
||||
run: |
|
||||
rm docker-compose.yml
|
||||
rm .env
|
||||
curl https://appwrite.io/install/compose -o docker-compose.yml
|
||||
curl https://appwrite.io/install/env -o .env
|
||||
sed -i 's/_APP_OPTIONS_ABUSE=enabled/_APP_OPTIONS_ABUSE=disabled/g' .env
|
||||
docker compose up -d
|
||||
sleep 10
|
||||
- name: Benchmark Latest
|
||||
run: oha -z 180s http://localhost/v1/health/version -j > benchmark-latest.json
|
||||
- name: Prepare comment
|
||||
run: |
|
||||
echo '## :sparkles: Benchmark results' > benchmark.txt
|
||||
echo ' ' >> benchmark.txt
|
||||
echo "- Requests per second: $(jq -r '.summary.requestsPerSec|tonumber?|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json)" >> benchmark.txt
|
||||
echo "- Requests with 200 status code: $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json)" >> benchmark.txt
|
||||
echo "- P99 latency: $(jq -r '.latencyPercentiles.p99' benchmark.json )" >> benchmark.txt
|
||||
echo " " >> benchmark.txt
|
||||
echo " " >> benchmark.txt
|
||||
echo "## :zap: Benchmark Comparison" >> benchmark.txt
|
||||
echo " " >> benchmark.txt
|
||||
echo "| Metric | This PR | Latest version | " >> benchmark.txt
|
||||
echo "| --- | --- | --- | " >> benchmark.txt
|
||||
echo "| RPS | $(jq -r '.summary.requestsPerSec|tonumber?|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json) | $(jq -r '.summary.requestsPerSec|tonumber|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark-latest.json) | " >> benchmark.txt
|
||||
echo "| 200 | $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json) | $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark-latest.json) | " >> benchmark.txt
|
||||
echo "| P99 | $(jq -r '.latencyPercentiles.p99' benchmark.json ) | $(jq -r '.latencyPercentiles.p99' benchmark-latest.json ) | " >> benchmark.txt
|
||||
- name: Save results
|
||||
uses: actions/upload-artifact@v4
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: benchmark.json
|
||||
path: benchmark.json
|
||||
retention-days: 7
|
||||
- name: Comment on PR
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
with:
|
||||
filePath: benchmark.txt
|
||||
|
|
Binary file not shown.
BIN
app/assets/dbip/dbip-country-lite-2024-08.mmdb
Normal file
BIN
app/assets/dbip/dbip-country-lite-2024-08.mmdb
Normal file
Binary file not shown.
|
@ -529,6 +529,11 @@ return [
|
|||
'description' => 'Synchronous function execution timed out. Use asynchronous execution instead, or ensure the execution duration doesn\'t exceed 30 seconds.',
|
||||
'code' => 408,
|
||||
],
|
||||
Exception::FUNCTION_TEMPLATE_NOT_FOUND => [
|
||||
'name' => Exception::FUNCTION_TEMPLATE_NOT_FOUND,
|
||||
'description' => 'Function Template with the requested ID could not be found.',
|
||||
'code' => 404,
|
||||
],
|
||||
|
||||
/** Builds */
|
||||
Exception::BUILD_NOT_FOUND => [
|
||||
|
|
2048
app/config/function-templates.php
Normal file
2048
app/config/function-templates.php
Normal file
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,8 @@ return [
|
|||
'magicSession',
|
||||
'recovery',
|
||||
'invitation',
|
||||
'mfaChallenge'
|
||||
'mfaChallenge',
|
||||
'sessionAlert'
|
||||
],
|
||||
'sms' => [
|
||||
'verification',
|
||||
|
|
|
@ -11,4 +11,4 @@
|
|||
<p>{{footer}}</p>
|
||||
|
||||
<p style="margin-bottom: 0px;">{{thanks}}</p>
|
||||
<p style="margin-top: 0px;">{{signature}}</p>
|
||||
<p style="margin-top: 0px;">{{signature}}</p>
|
|
@ -18,13 +18,13 @@
|
|||
"emails.magicSession.securityPhrase": "Security phrase for this email is {{b}}{{phrase}}{{/b}}. You can trust this email if this phrase matches the phrase shown during sign in.",
|
||||
"emails.magicSession.thanks": "Thanks,",
|
||||
"emails.magicSession.signature": "{{project}} team",
|
||||
"emails.sessionAlert.subject": "New session alert for {{project}}",
|
||||
"emails.sessionAlert.subject": "Security alert: new session on your {{project}} account",
|
||||
"emails.sessionAlert.hello":"Hello {{user}}",
|
||||
"emails.sessionAlert.body": "We're writing to inform you that a new session has been initiated on your {{b}}{{project}}{{/b}} account, on {{b}}{{dateTime}}{{/b}}. \nHere are the details of the new session: ",
|
||||
"emails.sessionAlert.body": "A new session has been created on your {{b}}{{project}}{{/b}} account, on {{b}}{{dateTime}}{{/b}}.\nHere are the details of the new session: ",
|
||||
"emails.sessionAlert.listDevice": "Device: {{b}}{{device}}{{/b}}",
|
||||
"emails.sessionAlert.listIpAddress": "IP Address: {{b}}{{ipAddress}}{{/b}}",
|
||||
"emails.sessionAlert.listCountry": "Country: {{b}}{{country}}{{/b}}",
|
||||
"emails.sessionAlert.footer": "If you didn't request the sign in, you can safely ignore this email. If you suspect unauthorized activity, please secure your account immediately.",
|
||||
"emails.sessionAlert.footer": "If this was you, there's nothing more you need to do.\nIf you didn't initiate this session or suspect any unauthorized activity, please secure your account.",
|
||||
"emails.sessionAlert.thanks": "Thanks,",
|
||||
"emails.sessionAlert.signature": "{{project}} team",
|
||||
"emails.otpSession.subject": "OTP for {{project}} Login",
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -124,7 +124,7 @@ function sendSessionAlert(Locale $locale, Document $user, Document $project, Doc
|
|||
|
||||
$emailVariables = [
|
||||
'direction' => $locale->getText('settings.direction'),
|
||||
'dateTime' => DateTime::format(new \DateTime(), 'Y-m-d H:i:s'),
|
||||
'dateTime' => DateTime::format(new \DateTime(), 'h:ia MMMM dS'),
|
||||
'user' => $user->getAttribute('name'),
|
||||
'project' => $project->getAttribute('name'),
|
||||
'device' => $session->getAttribute('clientName'),
|
||||
|
@ -224,7 +224,11 @@ $createSession = function (string $userId, string $secret, Request $request, Res
|
|||
}
|
||||
|
||||
if ($project->getAttribute('auths', [])['sessionAlerts'] ?? false) {
|
||||
sendSessionAlert($locale, $user, $project, $session, $queueForMails);
|
||||
if ($dbForProject->count('sessions', [
|
||||
Query::equal('userId', [$user->getId()]),
|
||||
]) !== 1) {
|
||||
sendSessionAlert($locale, $user, $project, $session, $queueForMails);
|
||||
}
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
|
@ -904,7 +908,11 @@ App::post('/v1/account/sessions/email')
|
|||
;
|
||||
|
||||
if ($project->getAttribute('auths', [])['sessionAlerts'] ?? false) {
|
||||
sendSessionAlert($locale, $user, $project, $session, $queueForMails);
|
||||
if ($dbForProject->count('sessions', [
|
||||
Query::equal('userId', [$user->getId()]),
|
||||
]) !== 1) {
|
||||
sendSessionAlert($locale, $user, $project, $session, $queueForMails);
|
||||
}
|
||||
}
|
||||
|
||||
$response->dynamic($session, Response::MODEL_SESSION);
|
||||
|
|
|
@ -1459,7 +1459,8 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/build')
|
|||
->inject('project')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForBuilds')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Request $request, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Build $queueForBuilds) {
|
||||
->inject('deviceForFunctions')
|
||||
->action(function (string $functionId, string $deploymentId, string $buildId, Request $request, Response $response, Database $dbForProject, Document $project, Event $queueForEvents, Build $queueForBuilds, Device $deviceForFunctions) {
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
if ($function->isEmpty()) {
|
||||
|
@ -1471,13 +1472,23 @@ App::post('/v1/functions/:functionId/deployments/:deploymentId/build')
|
|||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$path = $deployment->getAttribute('path');
|
||||
if(empty($path) || !$deviceForFunctions->exists($path)) {
|
||||
throw new Exception(Exception::DEPLOYMENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$deploymentId = ID::unique();
|
||||
|
||||
$destination = $deviceForFunctions->getPath($deploymentId . '.' . \pathinfo('code.tar.gz', PATHINFO_EXTENSION));
|
||||
$deviceForFunctions->transfer($path, $destination, $deviceForFunctions);
|
||||
|
||||
$deployment->removeAttribute('$internalId');
|
||||
$deployment = $dbForProject->createDocument('deployments', $deployment->setAttributes([
|
||||
'$internalId' => '',
|
||||
'$id' => $deploymentId,
|
||||
'buildId' => '',
|
||||
'buildInternalId' => '',
|
||||
'path' => $destination,
|
||||
'entrypoint' => $function->getAttribute('entrypoint'),
|
||||
'commands' => $function->getAttribute('commands', ''),
|
||||
'search' => implode(' ', [$deploymentId, $function->getAttribute('entrypoint')]),
|
||||
|
@ -2356,3 +2367,64 @@ App::delete('/v1/functions/:functionId/variables/:variableId')
|
|||
|
||||
$response->noContent();
|
||||
});
|
||||
|
||||
App::get('/v1/functions/templates')
|
||||
->desc('List function templates')
|
||||
->label('scope', 'public')
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'listTemplates')
|
||||
->label('sdk.description', '/docs/references/functions/list-templates.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TEMPLATE_FUNCTION_LIST)
|
||||
->param('runtimes', [], new ArrayList(new WhiteList(array_keys(Config::getParam('runtimes')), true), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of runtimes allowed for filtering function templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' runtimes are allowed.', true)
|
||||
->param('useCases', [], new ArrayList(new WhiteList(['dev-tools','starter','databases','ai','messaging','utilities']), APP_LIMIT_ARRAY_PARAMS_SIZE), 'List of use cases allowed for filtering function templates. Maximum of ' . APP_LIMIT_ARRAY_PARAMS_SIZE . ' use cases are allowed.', true)
|
||||
->param('limit', 25, new Range(1, 5000), 'Limit the number of templates returned in the response. Default limit is 25, and maximum limit is 5000.', true)
|
||||
->param('offset', 0, new Range(0, 5000), 'Offset the list of returned templates. Maximum offset is 5000.', true)
|
||||
->inject('response')
|
||||
->action(function (array $runtimes, array $usecases, int $limit, int $offset, Response $response) {
|
||||
$templates = Config::getParam('function-templates', []);
|
||||
|
||||
if (!empty($runtimes)) {
|
||||
$templates = \array_filter($templates, function ($template) use ($runtimes) {
|
||||
return \count(\array_intersect($runtimes, \array_column($template['runtimes'], 'name'))) > 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (!empty($usecases)) {
|
||||
$templates = \array_filter($templates, function ($template) use ($usecases) {
|
||||
return \count(\array_intersect($usecases, $template['useCases'])) > 0;
|
||||
});
|
||||
}
|
||||
|
||||
$responseTemplates = \array_slice($templates, $offset, $limit);
|
||||
$response->dynamic(new Document([
|
||||
'templates' => $responseTemplates,
|
||||
'total' => \count($responseTemplates),
|
||||
]), Response::MODEL_TEMPLATE_FUNCTION_LIST);
|
||||
});
|
||||
|
||||
App::get('/v1/functions/templates/:templateId')
|
||||
->desc('Get function template')
|
||||
->label('scope', 'public')
|
||||
->label('sdk.namespace', 'functions')
|
||||
->label('sdk.method', 'getTemplate')
|
||||
->label('sdk.description', '/docs/references/functions/get-template.md')
|
||||
->label('sdk.response.code', Response::STATUS_CODE_OK)
|
||||
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
|
||||
->label('sdk.response.model', Response::MODEL_TEMPLATE_FUNCTION)
|
||||
->param('templateId', '', new Text(128), 'Template ID.')
|
||||
->inject('response')
|
||||
->action(function (string $templateId, Response $response) {
|
||||
$templates = Config::getParam('function-templates', []);
|
||||
|
||||
$template = array_shift(\array_filter($templates, function ($template) use ($templateId) {
|
||||
return $template['id'] === $templateId;
|
||||
}));
|
||||
|
||||
if (empty($template)) {
|
||||
throw new Exception(Exception::FUNCTION_TEMPLATE_NOT_FOUND);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document($template), Response::MODEL_TEMPLATE_FUNCTION);
|
||||
});
|
||||
|
|
|
@ -304,6 +304,7 @@ Config::load('storage-logos', __DIR__ . '/config/storage/logos.php');
|
|||
Config::load('storage-mimes', __DIR__ . '/config/storage/mimes.php');
|
||||
Config::load('storage-inputs', __DIR__ . '/config/storage/inputs.php');
|
||||
Config::load('storage-outputs', __DIR__ . '/config/storage/outputs.php');
|
||||
Config::load('function-templates', __DIR__ . '/config/function-templates.php');
|
||||
|
||||
/**
|
||||
* New DB Filters
|
||||
|
@ -1013,7 +1014,7 @@ $register->set('smtp', function () {
|
|||
return $mail;
|
||||
});
|
||||
$register->set('geodb', function () {
|
||||
return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2024-02.mmdb');
|
||||
return new Reader(__DIR__ . '/assets/dbip/dbip-country-lite-2024-08.mmdb');
|
||||
});
|
||||
$register->set('passwordsDictionary', function () {
|
||||
$content = \file_get_contents(__DIR__ . '/assets/security/10k-common-passwords');
|
||||
|
|
|
@ -787,7 +787,7 @@ $image = $this->getParam('image', '');
|
|||
<<: *x-logging
|
||||
restart: unless-stopped
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/executor:0.5.5
|
||||
image: openruntimes/executor:0.6.5
|
||||
networks:
|
||||
- appwrite
|
||||
- runtimes
|
||||
|
|
46
composer.lock
generated
46
composer.lock
generated
|
@ -1721,16 +1721,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/database",
|
||||
"version": "0.50.0",
|
||||
"version": "0.50.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/database.git",
|
||||
"reference": "ce3eaccb2f3bbd34b2b97419836fec633b26b8f7"
|
||||
"reference": "c712d1f6c8ec37886a7a1ad4d60a8cd75dec00aa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/ce3eaccb2f3bbd34b2b97419836fec633b26b8f7",
|
||||
"reference": "ce3eaccb2f3bbd34b2b97419836fec633b26b8f7",
|
||||
"url": "https://api.github.com/repos/utopia-php/database/zipball/c712d1f6c8ec37886a7a1ad4d60a8cd75dec00aa",
|
||||
"reference": "c712d1f6c8ec37886a7a1ad4d60a8cd75dec00aa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1771,9 +1771,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/database/issues",
|
||||
"source": "https://github.com/utopia-php/database/tree/0.50.0"
|
||||
"source": "https://github.com/utopia-php/database/tree/0.50.2"
|
||||
},
|
||||
"time": "2024-06-21T03:21:42+00:00"
|
||||
"time": "2024-07-31T10:12:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/domains",
|
||||
|
@ -1923,16 +1923,16 @@
|
|||
},
|
||||
{
|
||||
"name": "utopia-php/framework",
|
||||
"version": "0.33.6",
|
||||
"version": "0.33.7",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/http.git",
|
||||
"reference": "8fe57da0cecd57e3b17cd395b4a666a24f4c07a6"
|
||||
"reference": "78d293d99a262bd63ece750bbf989c7e0643b825"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/8fe57da0cecd57e3b17cd395b4a666a24f4c07a6",
|
||||
"reference": "8fe57da0cecd57e3b17cd395b4a666a24f4c07a6",
|
||||
"url": "https://api.github.com/repos/utopia-php/http/zipball/78d293d99a262bd63ece750bbf989c7e0643b825",
|
||||
"reference": "78d293d99a262bd63ece750bbf989c7e0643b825",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1962,9 +1962,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/http/issues",
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.6"
|
||||
"source": "https://github.com/utopia-php/http/tree/0.33.7"
|
||||
},
|
||||
"time": "2024-03-21T18:10:57+00:00"
|
||||
"time": "2024-08-01T14:01:04+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/image",
|
||||
|
@ -2990,16 +2990,16 @@
|
|||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "0.39.3",
|
||||
"version": "0.39.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "16142d88270e368030d7956cadf2d7816413f8c4"
|
||||
"reference": "501b92d73ae55e0f880ed00f57bc64a54d0ce137"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/16142d88270e368030d7956cadf2d7816413f8c4",
|
||||
"reference": "16142d88270e368030d7956cadf2d7816413f8c4",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/501b92d73ae55e0f880ed00f57bc64a54d0ce137",
|
||||
"reference": "501b92d73ae55e0f880ed00f57bc64a54d0ce137",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3035,9 +3035,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/0.39.3"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/0.39.4"
|
||||
},
|
||||
"time": "2024-07-12T15:29:48+00:00"
|
||||
"time": "2024-07-26T22:34:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "doctrine/deprecations",
|
||||
|
@ -3158,16 +3158,16 @@
|
|||
},
|
||||
{
|
||||
"name": "laravel/pint",
|
||||
"version": "v1.16.2",
|
||||
"version": "v1.17.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/pint.git",
|
||||
"reference": "51f1ba679a6afe0315621ad143d788bd7ded0eca"
|
||||
"reference": "b5b6f716db298671c1dfea5b1082ec2c0ae7064f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/pint/zipball/51f1ba679a6afe0315621ad143d788bd7ded0eca",
|
||||
"reference": "51f1ba679a6afe0315621ad143d788bd7ded0eca",
|
||||
"url": "https://api.github.com/repos/laravel/pint/zipball/b5b6f716db298671c1dfea5b1082ec2c0ae7064f",
|
||||
"reference": "b5b6f716db298671c1dfea5b1082ec2c0ae7064f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -3220,7 +3220,7 @@
|
|||
"issues": "https://github.com/laravel/pint/issues",
|
||||
"source": "https://github.com/laravel/pint"
|
||||
},
|
||||
"time": "2024-07-09T15:58:08+00:00"
|
||||
"time": "2024-08-01T09:06:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "matthiasmullie/minify",
|
||||
|
|
|
@ -873,7 +873,7 @@ services:
|
|||
hostname: exc1
|
||||
<<: *x-logging
|
||||
stop_signal: SIGINT
|
||||
image: openruntimes/executor:0.6.1
|
||||
image: openruntimes/executor:0.6.5
|
||||
restart: unless-stopped
|
||||
networks:
|
||||
- appwrite
|
||||
|
|
1
docs/references/functions/get-template.md
Normal file
1
docs/references/functions/get-template.md
Normal file
|
@ -0,0 +1 @@
|
|||
Get a function template using ID. You can use template details in [createFunction](/docs/references/cloud/server-nodejs/functions#create) method.
|
1
docs/references/functions/list-templates.md
Normal file
1
docs/references/functions/list-templates.md
Normal file
|
@ -0,0 +1 @@
|
|||
List available function templates. You can use template details in [createFunction](/docs/references/cloud/server-nodejs/functions#create) method.
|
|
@ -156,6 +156,7 @@ class Exception extends \Exception
|
|||
public const FUNCTION_RUNTIME_UNSUPPORTED = 'function_runtime_unsupported';
|
||||
public const FUNCTION_ENTRYPOINT_MISSING = 'function_entrypoint_missing';
|
||||
public const FUNCTION_SYNCHRONOUS_TIMEOUT = 'function_synchronous_timeout';
|
||||
public const FUNCTION_TEMPLATE_NOT_FOUND = 'function_template_not_found';
|
||||
|
||||
/** Deployments */
|
||||
public const DEPLOYMENT_NOT_FOUND = 'deployment_not_found';
|
||||
|
|
|
@ -235,7 +235,7 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|||
->setTwitter(APP_SOCIAL_TWITTER_HANDLE)
|
||||
->setDiscord(APP_SOCIAL_DISCORD_CHANNEL, APP_SOCIAL_DISCORD)
|
||||
->setDefaultHeaders([
|
||||
'X-Appwrite-Response-Format' => '1.5.0',
|
||||
'X-Appwrite-Response-Format' => '1.6.0',
|
||||
]);
|
||||
|
||||
// Make sure we have a clean slate.
|
||||
|
|
|
@ -333,6 +333,7 @@ class Builds extends Action
|
|||
$source = $path;
|
||||
|
||||
$build = $dbForProject->updateDocument('builds', $build->getId(), $build->setAttribute('source', $source));
|
||||
$deployment = $dbForProject->updateDocument('deployments', $deployment->getId(), $deployment->setAttribute('path', $source));
|
||||
|
||||
$this->runGitAction('processing', $github, $providerCommitHash, $owner, $repositoryName, $project, $function, $deployment->getId(), $dbForProject, $dbForConsole);
|
||||
}
|
||||
|
|
|
@ -136,7 +136,11 @@ class BodyMultipart
|
|||
}
|
||||
|
||||
$query .= $eol . $eol;
|
||||
$query .= $value . $eol;
|
||||
if ($value === false) {
|
||||
$query .= 0 . $eol;
|
||||
} else {
|
||||
$query .= $value . $eol;
|
||||
}
|
||||
$query .= '--' . $this->boundary;
|
||||
}
|
||||
|
||||
|
|
|
@ -87,7 +87,10 @@ use Appwrite\Utopia\Response\Model\Subscriber;
|
|||
use Appwrite\Utopia\Response\Model\Target;
|
||||
use Appwrite\Utopia\Response\Model\Team;
|
||||
use Appwrite\Utopia\Response\Model\TemplateEmail;
|
||||
use Appwrite\Utopia\Response\Model\TemplateFunction;
|
||||
use Appwrite\Utopia\Response\Model\TemplateRuntime;
|
||||
use Appwrite\Utopia\Response\Model\TemplateSMS;
|
||||
use Appwrite\Utopia\Response\Model\TemplateVariable;
|
||||
use Appwrite\Utopia\Response\Model\Token;
|
||||
use Appwrite\Utopia\Response\Model\Topic;
|
||||
use Appwrite\Utopia\Response\Model\UsageBuckets;
|
||||
|
@ -251,6 +254,10 @@ class Response extends SwooleResponse
|
|||
public const MODEL_BUILD_LIST = 'buildList'; // Not used anywhere yet
|
||||
public const MODEL_FUNC_PERMISSIONS = 'funcPermissions';
|
||||
public const MODEL_HEADERS = 'headers';
|
||||
public const MODEL_TEMPLATE_FUNCTION = 'templateFunction';
|
||||
public const MODEL_TEMPLATE_FUNCTION_LIST = 'templateFunctionList';
|
||||
public const MODEL_TEMPLATE_RUNTIME = 'templateRuntime';
|
||||
public const MODEL_TEMPLATE_VARIABLE = 'templateVariable';
|
||||
|
||||
// Proxy
|
||||
public const MODEL_PROXY_RULE = 'proxyRule';
|
||||
|
@ -340,6 +347,7 @@ class Response extends SwooleResponse
|
|||
->setModel(new BaseList('Teams List', self::MODEL_TEAM_LIST, 'teams', self::MODEL_TEAM))
|
||||
->setModel(new BaseList('Memberships List', self::MODEL_MEMBERSHIP_LIST, 'memberships', self::MODEL_MEMBERSHIP))
|
||||
->setModel(new BaseList('Functions List', self::MODEL_FUNCTION_LIST, 'functions', self::MODEL_FUNCTION))
|
||||
->setModel(new BaseList('Function Templates List', self::MODEL_TEMPLATE_FUNCTION_LIST, 'templates', self::MODEL_TEMPLATE_FUNCTION))
|
||||
->setModel(new BaseList('Installations List', self::MODEL_INSTALLATION_LIST, 'installations', self::MODEL_INSTALLATION))
|
||||
->setModel(new BaseList('Provider Repositories List', self::MODEL_PROVIDER_REPOSITORY_LIST, 'providerRepositories', self::MODEL_PROVIDER_REPOSITORY))
|
||||
->setModel(new BaseList('Branches List', self::MODEL_BRANCH_LIST, 'branches', self::MODEL_BRANCH))
|
||||
|
@ -409,6 +417,9 @@ class Response extends SwooleResponse
|
|||
->setModel(new Team())
|
||||
->setModel(new Membership())
|
||||
->setModel(new Func())
|
||||
->setModel(new TemplateFunction())
|
||||
->setModel(new TemplateRuntime())
|
||||
->setModel(new TemplateVariable())
|
||||
->setModel(new Installation())
|
||||
->setModel(new ProviderRepository())
|
||||
->setModel(new Detection())
|
||||
|
|
136
src/Appwrite/Utopia/Response/Model/TemplateFunction.php
Normal file
136
src/Appwrite/Utopia/Response/Model/TemplateFunction.php
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class TemplateFunction extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('icon', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function Template Icon.',
|
||||
'default' => '',
|
||||
'example' => 'icon-lightning-bolt',
|
||||
])
|
||||
->addRule('id', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function Template ID.',
|
||||
'default' => '',
|
||||
'example' => 'starter',
|
||||
])
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function Template Name.',
|
||||
'default' => '',
|
||||
'example' => 'Starter function',
|
||||
])
|
||||
->addRule('tagline', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function Template Tagline.',
|
||||
'default' => '',
|
||||
'example' => 'A simple function to get started.',
|
||||
])
|
||||
->addRule('permissions', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Execution permissions.',
|
||||
'default' => [],
|
||||
'example' => 'any',
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('events', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function trigger events.',
|
||||
'default' => [],
|
||||
'example' => 'account.create',
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('cron', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function execution schedult in CRON format.',
|
||||
'default' => '',
|
||||
'example' => '0 0 * * *',
|
||||
])
|
||||
->addRule('timeout', [
|
||||
'type' => self::TYPE_INTEGER,
|
||||
'description' => 'Function execution timeout in seconds.',
|
||||
'default' => 15,
|
||||
'example' => 300,
|
||||
])
|
||||
->addRule('useCases', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function use cases.',
|
||||
'default' => [],
|
||||
'example' => 'Starter',
|
||||
'array' => true,
|
||||
])
|
||||
->addRule('runtimes', [
|
||||
'type' => Response::MODEL_TEMPLATE_RUNTIME,
|
||||
'description' => 'List of runtimes that can be used with this template.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
->addRule('instructions', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Function Template Instructions.',
|
||||
'default' => '',
|
||||
'example' => 'For documentation and instructions check out <link>.',
|
||||
])
|
||||
->addRule('vcsProvider', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'VCS (Version Control System) Provider.',
|
||||
'default' => '',
|
||||
'example' => 'github',
|
||||
])
|
||||
->addRule('providerRepositoryId', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'VCS (Version Control System) Repository ID',
|
||||
'default' => '',
|
||||
'example' => 'templates',
|
||||
])
|
||||
->addRule('providerOwner', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'VCS (Version Control System) Owner.',
|
||||
'default' => '',
|
||||
'example' => 'appwrite',
|
||||
])
|
||||
->addRule('providerBranch', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'VCS (Version Control System) branch name',
|
||||
'default' => '',
|
||||
'example' => 'main',
|
||||
])
|
||||
->addRule('variables', [
|
||||
'type' => Response::MODEL_TEMPLATE_VARIABLE,
|
||||
'description' => 'Function variables.',
|
||||
'default' => [],
|
||||
'example' => [],
|
||||
'array' => true
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Template Function';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_TEMPLATE_FUNCTION;
|
||||
}
|
||||
}
|
59
src/Appwrite/Utopia/Response/Model/TemplateRuntime.php
Normal file
59
src/Appwrite/Utopia/Response/Model/TemplateRuntime.php
Normal file
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class TemplateRuntime extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Runtime Name.',
|
||||
'default' => '',
|
||||
'example' => 'node-19.0',
|
||||
])
|
||||
->addRule('commands', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The build command used to build the deployment.',
|
||||
'default' => '',
|
||||
'example' => 'npm install',
|
||||
])
|
||||
->addRule('entrypoint', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'The entrypoint file used to execute the deployment.',
|
||||
'default' => '',
|
||||
'example' => 'index.js',
|
||||
])
|
||||
->addRule('providerRootDirectory', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Path to function in VCS (Version Control System) repository',
|
||||
'default' => '',
|
||||
'example' => 'node/starter',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Template Runtime';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_TEMPLATE_RUNTIME;
|
||||
}
|
||||
}
|
65
src/Appwrite/Utopia/Response/Model/TemplateVariable.php
Normal file
65
src/Appwrite/Utopia/Response/Model/TemplateVariable.php
Normal file
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Response\Model;
|
||||
|
||||
use Appwrite\Utopia\Response;
|
||||
use Appwrite\Utopia\Response\Model;
|
||||
|
||||
class TemplateVariable extends Model
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this
|
||||
->addRule('name', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Variable Name.',
|
||||
'default' => '',
|
||||
'example' => 'APPWRITE_DATABASE_ID',
|
||||
])
|
||||
->addRule('description', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Variable Description.',
|
||||
'default' => '',
|
||||
'example' => 'The ID of the Appwrite database that contains the collection to sync.',
|
||||
])
|
||||
->addRule('placeholder', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Variable Placeholder.',
|
||||
'default' => '',
|
||||
'example' => '64a55...7b912',
|
||||
])
|
||||
->addRule('required', [
|
||||
'type' => self::TYPE_BOOLEAN,
|
||||
'description' => 'Is the variable required?',
|
||||
'default' => false,
|
||||
'example' => false,
|
||||
])
|
||||
->addRule('type', [
|
||||
'type' => self::TYPE_STRING,
|
||||
'description' => 'Variable Type.',
|
||||
'default' => '',
|
||||
'example' => 'password',
|
||||
])
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return 'Template Variable';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return Response::MODEL_TEMPLATE_VARIABLE;
|
||||
}
|
||||
}
|
|
@ -168,6 +168,7 @@ class Executor
|
|||
* @param string $source
|
||||
* @param string $entrypoint
|
||||
* @param string $runtimeEntrypoint
|
||||
* @param bool $logging
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
|
@ -193,8 +194,7 @@ class Executor
|
|||
}
|
||||
|
||||
$runtimeId = "$projectId-$deploymentId";
|
||||
$route = '/runtimes/' . $runtimeId . '/execution';
|
||||
|
||||
$route = '/runtimes/' . $runtimeId . '/executions';
|
||||
|
||||
// Remove after migration
|
||||
if ($version == 'v3') {
|
||||
|
@ -216,6 +216,7 @@ class Executor
|
|||
'version' => $version,
|
||||
'runtimeEntrypoint' => $runtimeEntrypoint,
|
||||
'logging' => $logging,
|
||||
'restartPolicy' => 'always' // Once utopia/orchestration has it, use DockerAPI::ALWAYS (0.13+)
|
||||
];
|
||||
|
||||
if(!empty($body)) {
|
||||
|
|
|
@ -1225,7 +1225,7 @@ class AccountCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
// Create a session for the new account
|
||||
// Create first session for the new account
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1238,11 +1238,23 @@ class AccountCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(201, $response['headers']['status-code']);
|
||||
|
||||
// Create second session for the new account
|
||||
$response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([
|
||||
'origin' => 'http://localhost',
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
|
||||
]), [
|
||||
'email' => $email,
|
||||
'password' => $password,
|
||||
]);
|
||||
|
||||
|
||||
// Check the alert email
|
||||
$lastEmail = $this->getLastEmail();
|
||||
|
||||
$this->assertEquals($email, $lastEmail['to'][0]['address']);
|
||||
$this->assertStringContainsString('New session alert', $lastEmail['subject']);
|
||||
$this->assertStringContainsString('Security alert: new session', $lastEmail['subject']);
|
||||
$this->assertStringContainsString($response['body']['ip'], $lastEmail['text']); // IP Address
|
||||
$this->assertStringContainsString('Unknown', $lastEmail['text']); // Country
|
||||
$this->assertStringContainsString($response['body']['clientName'], $lastEmail['text']); // Client name
|
||||
|
|
|
@ -15,6 +15,31 @@ trait FunctionsBase
|
|||
Console::execute('cd ' . realpath(__DIR__ . "/../../../resources/functions") . "/$folder && tar --exclude code.tar.gz -czf code.tar.gz .", '', $this->stdout, $this->stderr);
|
||||
}
|
||||
|
||||
protected function awaitDeploymentIsBuilt($functionId, $deploymentId, $checkForSuccess = true): void
|
||||
{
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
if($checkForSuccess) {
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertEquals('ready', $deployment['body']['status'], \json_encode($deployment['body']));
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * @depends testCreateTeam
|
||||
// */
|
||||
|
|
|
@ -8,6 +8,7 @@ use Tests\E2E\Client;
|
|||
use Tests\E2E\Scopes\ProjectCustom;
|
||||
use Tests\E2E\Scopes\Scope;
|
||||
use Tests\E2E\Scopes\SideClient;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\DateTime;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Helpers\ID;
|
||||
|
@ -120,25 +121,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
$this->assertEquals('ready', $deployment['body']['status'], \json_encode($deployment['body']));
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
|
@ -239,25 +222,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
$this->assertEquals('ready', $deployment['body']['status']);
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
|
@ -418,25 +383,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
$this->assertEquals('ready', $deployment['body']['status'], \json_encode($deployment['body']));
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
|
@ -548,25 +495,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
$this->assertEquals('ready', $deployment['body']['status']);
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
|
||||
|
||||
// Why do we have to do this?
|
||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
|
||||
|
@ -805,25 +734,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
$this->assertEquals('ready', $deployment['body']['status']);
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
|
||||
|
||||
$function = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
|
@ -916,25 +827,7 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
$this->assertEquals('ready', $deployment['body']['status']);
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -963,4 +856,131 @@ class FunctionsCustomClientTest extends Scope
|
|||
|
||||
return [];
|
||||
}
|
||||
|
||||
public function testListTemplates()
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$expectedTemplates = array_slice(Config::getParam('function-templates', []), 0, 25);
|
||||
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(200, $templates['headers']['status-code']);
|
||||
$this->assertGreaterThan(0, $templates['body']['total']);
|
||||
$this->assertIsArray($templates['body']['templates']);
|
||||
$this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]);
|
||||
$this->assertArrayHasKey('useCases', $templates['body']['templates'][0]);
|
||||
for ($i = 0; $i < 25; $i++) {
|
||||
$this->assertEquals($expectedTemplates[$i]['name'], $templates['body']['templates'][$i]['name']);
|
||||
$this->assertEquals($expectedTemplates[$i]['id'], $templates['body']['templates'][$i]['id']);
|
||||
$this->assertEquals($expectedTemplates[$i]['icon'], $templates['body']['templates'][$i]['icon']);
|
||||
$this->assertEquals($expectedTemplates[$i]['tagline'], $templates['body']['templates'][$i]['tagline']);
|
||||
$this->assertEquals($expectedTemplates[$i]['useCases'], $templates['body']['templates'][$i]['useCases']);
|
||||
$this->assertEquals($expectedTemplates[$i]['vcsProvider'], $templates['body']['templates'][$i]['vcsProvider']);
|
||||
$this->assertEquals($expectedTemplates[$i]['runtimes'], $templates['body']['templates'][$i]['runtimes']);
|
||||
$this->assertEquals($expectedTemplates[$i]['variables'], $templates['body']['templates'][$i]['variables']);
|
||||
}
|
||||
|
||||
$templates_offset = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
], $this->getHeaders()), [
|
||||
'limit' => 1,
|
||||
'offset' => 2
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $templates_offset['headers']['status-code']);
|
||||
$this->assertEquals(1, $templates_offset['body']['total']);
|
||||
// assert that offset works as expected
|
||||
$this->assertEquals($templates['body']['templates'][2]['id'], $templates_offset['body']['templates'][0]['id']);
|
||||
|
||||
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
], $this->getHeaders()), [
|
||||
'useCases' => ['starter', 'ai'],
|
||||
'runtimes' => ['bun-1.0', 'dart-2.16']
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $templates['headers']['status-code']);
|
||||
$this->assertGreaterThanOrEqual(3, $templates['body']['total']);
|
||||
$this->assertIsArray($templates['body']['templates']);
|
||||
foreach ($templates['body']['templates'] as $template) {
|
||||
$this->assertContains($template['useCases'][0], ['starter', 'ai']);
|
||||
}
|
||||
$this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]);
|
||||
$this->assertContains('bun-1.0', array_column($templates['body']['templates'][0]['runtimes'], 'name'));
|
||||
|
||||
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'limit' => 5,
|
||||
'offset' => 2,
|
||||
'useCases' => ['databases'],
|
||||
'runtimes' => ['node-16.0']
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $templates['headers']['status-code']);
|
||||
$this->assertEquals(5, $templates['body']['total']);
|
||||
$this->assertIsArray($templates['body']['templates']);
|
||||
$this->assertArrayHasKey('runtimes', $templates['body']['templates'][0]);
|
||||
foreach ($templates['body']['templates'] as $template) {
|
||||
$this->assertContains($template['useCases'][0], ['databases']);
|
||||
}
|
||||
$this->assertContains('node-16.0', array_column($templates['body']['templates'][0]['runtimes'], 'name'));
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
], $this->getHeaders()), [
|
||||
'limit' => 5001,
|
||||
'offset' => 10,
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $templates['headers']['status-code']);
|
||||
$this->assertEquals('Invalid `limit` param: Value must be a valid range between 1 and 5,000', $templates['body']['message']);
|
||||
|
||||
$templates = $this->client->call(Client::METHOD_GET, '/functions/templates', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'limit' => 5,
|
||||
'offset' => 5001,
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $templates['headers']['status-code']);
|
||||
$this->assertEquals('Invalid `offset` param: Value must be a valid range between 0 and 5,000', $templates['body']['message']);
|
||||
}
|
||||
|
||||
public function testGetTemplate()
|
||||
{
|
||||
/**
|
||||
* Test for SUCCESS
|
||||
*/
|
||||
$template = $this->client->call(Client::METHOD_GET, '/functions/templates/query-neo4j-auradb', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(200, $template['headers']['status-code']);
|
||||
$this->assertIsArray($template['body']);
|
||||
$this->assertEquals('query-neo4j-auradb', $template['body']['id']);
|
||||
$this->assertEquals('Query Neo4j AuraDB', $template['body']['name']);
|
||||
$this->assertEquals('icon-neo4j', $template['body']['icon']);
|
||||
$this->assertEquals('Graph database with focus on relations between data.', $template['body']['tagline']);
|
||||
$this->assertEquals(['databases'], $template['body']['useCases']);
|
||||
$this->assertEquals('github', $template['body']['vcsProvider']);
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
$template = $this->client->call(Client::METHOD_GET, '/functions/templates/invalid-template-id', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
], $this->getHeaders()), []);
|
||||
|
||||
$this->assertEquals(404, $template['headers']['status-code']);
|
||||
$this->assertEquals('Function Template with the requested ID could not be found.', $template['body']['message']);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -426,25 +426,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
$this->assertEquals('ready', $deployment['body']['status'], \json_encode($deployment['body']));
|
||||
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId);
|
||||
|
||||
$functionDetails = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
|
@ -483,26 +465,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$this->assertEquals(true, (new DatetimeValidator())->isValid($deployment['body']['$createdAt']));
|
||||
$this->assertEquals('index.php', $deployment['body']['entrypoint']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $data['functionId'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
$this->assertEquals(200, $deployment['headers']['status-code']);
|
||||
$this->assertEquals('ready', $deployment['body']['status']);
|
||||
$this->awaitDeploymentIsBuilt($data['functionId'], $deploymentId);
|
||||
|
||||
return array_merge($data, ['deploymentId' => $deploymentId]);
|
||||
}
|
||||
|
@ -1167,25 +1130,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $functionId . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
|
||||
$this->assertEquals('ready', $deployment['body']['status']);
|
||||
$this->awaitDeploymentIsBuilt($functionId, $deploymentId);
|
||||
|
||||
$execution = $this->client->call(Client::METHOD_POST, '/functions/' . $functionId . '/executions', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1264,7 +1209,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
* @param string $entrypoint
|
||||
*
|
||||
* @dataProvider provideCustomExecutions
|
||||
* @depends testTimeout
|
||||
* @depends testTimeout
|
||||
*/
|
||||
public function testCreateCustomExecution(string $folder, string $name, string $entrypoint, string $runtimeName, string $runtimeVersion)
|
||||
{
|
||||
|
@ -1310,23 +1255,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1435,23 +1364,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1543,23 +1456,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1654,23 +1551,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1738,23 +1619,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1845,23 +1710,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -1948,23 +1797,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -2050,23 +1883,7 @@ class FunctionsCustomServerTest extends Scope
|
|||
$deploymentId = $deployment['body']['$id'] ?? '';
|
||||
$this->assertEquals(202, $deployment['headers']['status-code']);
|
||||
|
||||
// Poll until deployment is built
|
||||
while (true) {
|
||||
$deployment = $this->client->call(Client::METHOD_GET, '/functions/' . $function['body']['$id'] . '/deployments/' . $deploymentId, [
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey'],
|
||||
]);
|
||||
|
||||
if (
|
||||
$deployment['headers']['status-code'] >= 400
|
||||
|| \in_array($deployment['body']['status'], ['ready', 'failed'])
|
||||
) {
|
||||
break;
|
||||
}
|
||||
|
||||
\sleep(1);
|
||||
}
|
||||
$this->awaitDeploymentIsBuilt($function['body']['$id'], $deploymentId, checkForSuccess: false);
|
||||
|
||||
$deployment = $this->client->call(Client::METHOD_PATCH, '/functions/' . $functionId . '/deployments/' . $deploymentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
|
@ -2081,9 +1898,9 @@ class FunctionsCustomServerTest extends Scope
|
|||
$proxyClient = new Client();
|
||||
$proxyClient->setEndpoint('http://' . $domain);
|
||||
|
||||
$bytes = pack('C*', ...[0,20,255]);
|
||||
$bytes = pack('C*', ...[0, 20, 255]);
|
||||
|
||||
$response = $proxyClient->call(Client::METHOD_POST, '/', [ 'content-type' => 'text/plain' ], $bytes, false);
|
||||
$response = $proxyClient->call(Client::METHOD_POST, '/', ['content-type' => 'text/plain'], $bytes, false);
|
||||
|
||||
$this->assertEquals(200, $response['headers']['status-code']);
|
||||
$this->assertEquals(\md5($bytes), $response['body']);
|
||||
|
|
Loading…
Reference in a new issue