This commit is contained in:
Chirag Aggarwal
2026-02-21 21:04:23 +05:30
parent a907c9df34
commit 9521f12860
9 changed files with 264 additions and 4 deletions
+11
View File
@@ -831,6 +831,17 @@ return [
'array' => true,
'filters' => [],
],
[
'$id' => ID::custom('deploymentBadge'),
'type' => Database::VAR_BOOLEAN,
'signed' => true,
'size' => 0,
'format' => '',
'filters' => [],
'required' => false,
'default' => false,
'array' => false,
],
],
'indexes' => [
[
+1
View File
@@ -38,6 +38,7 @@
<file>./tests/e2e/Services/Functions/FunctionsBase.php</file>
<file>./tests/e2e/Services/Functions/FunctionsCustomServerTest.php</file>
<file>./tests/e2e/Services/Functions/FunctionsCustomClientTest.php</file>
<directory>./tests/e2e/Services/Badge</directory>
</testsuite>
</testsuites>
</phpunit>
@@ -53,7 +53,7 @@ class Get extends Action
$message = 'not found';
$color = 'lightgrey';
break;
case !$function->getAttribute('deploymentBadge', true):
case !$function->getAttribute('deploymentBadge', false):
$message = 'disabled';
$color = 'lightgrey';
break;
@@ -53,7 +53,7 @@ class Get extends Action
$message = 'not found';
$color = 'lightgrey';
break;
case !$site->getAttribute('deploymentBadge', true):
case !$site->getAttribute('deploymentBadge', false):
$message = 'disabled';
$color = 'lightgrey';
break;
@@ -93,6 +93,7 @@ class Update extends Base
System::getEnv('_APP_COMPUTE_CPUS', 0),
System::getEnv('_APP_COMPUTE_MEMORY', 0)
), 'Runtime specification for the function and builds.', true, ['plan'])
->param('deploymentBadge', null, new Nullable(new Boolean()), 'Whether to display the deployment badge for this function.', true)
->inject('request')
->inject('response')
->inject('dbForProject')
@@ -125,6 +126,7 @@ class Update extends Base
bool $providerSilentMode,
string $providerRootDirectory,
string $specification,
?bool $deploymentBadge,
Request $request,
Response $response,
Database $dbForProject,
@@ -240,6 +242,8 @@ class Update extends Base
}
}
$deploymentBadge ??= $function->getAttribute('deploymentBadge', false);
$function = $dbForProject->updateDocument('functions', $function->getId(), new Document(array_merge($function->getArrayCopy(), [
'execute' => $execute,
'name' => $name,
@@ -266,6 +270,7 @@ class Update extends Base
'specification' => $specification,
'buildSpecification' => $specification,
'runtimeSpecification' => $specification,
'deploymentBadge' => $deploymentBadge,
'search' => implode(' ', [$functionId, $name, $runtime]),
])));
@@ -164,7 +164,7 @@ class Update extends Base
}
if ($request->getPayload('deploymentBadge', null) === null) {
$deploymentBadge = $site->getAttribute('deploymentBadge', true);
$deploymentBadge = $site->getAttribute('deploymentBadge', false);
}
$enabled ??= $site->getAttribute('enabled', true);
@@ -182,6 +182,12 @@ class Func extends Model
'default' => APP_COMPUTE_SPECIFICATION_DEFAULT,
'example' => APP_COMPUTE_SPECIFICATION_DEFAULT,
])
->addRule('deploymentBadge', [
'type' => self::TYPE_BOOLEAN,
'description' => 'Whether to display the deployment badge in the function response.',
'default' => false,
'example' => false,
])
;
}
+1 -1
View File
@@ -188,7 +188,7 @@ class Site extends Model
->addRule('deploymentBadge', [
'type' => self::TYPE_BOOLEAN,
'description' => 'Whether to display the deployment badge in the site response.',
'default' => true,
'default' => false,
'example' => false,
])
;
+237
View File
@@ -0,0 +1,237 @@
<?php
namespace Tests\E2E\Services\Badge;
use Tests\E2E\Client;
use Tests\E2E\Scopes\ProjectCustom;
use Tests\E2E\Scopes\Scope;
use Tests\E2E\Scopes\SideConsole;
use Utopia\Database\Helpers\ID;
class BadgeTest extends Scope
{
use ProjectCustom;
use SideConsole;
public function testGetSiteBadgeNotFound(): void
{
$response = $this->client->call(Client::METHOD_GET, '/badge/sites/nonexistentid1234567', [
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('image/svg+xml', $response['headers']['content-type']);
$this->assertStringContainsString('<svg', $response['body']);
$this->assertStringContainsString('not found', $response['body']);
$this->assertStringContainsString('appwrite sites', $response['body']);
}
public function testGetFunctionBadgeNotFound(): void
{
$response = $this->client->call(Client::METHOD_GET, '/badge/functions/nonexistentid1234567', [
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('image/svg+xml', $response['headers']['content-type']);
$this->assertStringContainsString('<svg', $response['body']);
$this->assertStringContainsString('not found', $response['body']);
$this->assertStringContainsString('appwrite functions', $response['body']);
}
/**
* deploymentBadge defaults to false — a new site shows 'disabled' without any extra step.
*/
public function testGetSiteBadgeDisabledByDefault(): void
{
$site = $this->client->call(Client::METHOD_POST, '/sites', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'siteId' => ID::unique(),
'name' => 'Badge Disabled Site',
'framework' => 'other',
'adapter' => 'static',
'buildRuntime' => 'static-1',
'outputDirectory' => './',
'buildCommand' => '',
'installCommand' => '',
'fallbackFile' => '',
]);
$this->assertEquals(201, $site['headers']['status-code']);
$siteId = $site['body']['$id'];
$response = $this->client->call(Client::METHOD_GET, '/badge/sites/' . $siteId, [
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('image/svg+xml', $response['headers']['content-type']);
$this->assertStringContainsString('<svg', $response['body']);
$this->assertStringContainsString('disabled', $response['body']);
$this->assertStringContainsString('appwrite sites', $response['body']);
$this->client->call(Client::METHOD_DELETE, '/sites/' . $siteId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
}
/**
* deploymentBadge defaults to false — a new function shows 'disabled' without any extra step.
*/
public function testGetFunctionBadgeDisabledByDefault(): void
{
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'functionId' => ID::unique(),
'name' => 'Badge Disabled Function',
'runtime' => 'node-22',
'entrypoint' => 'index.js',
]);
$this->assertEquals(201, $function['headers']['status-code']);
$functionId = $function['body']['$id'];
$response = $this->client->call(Client::METHOD_GET, '/badge/functions/' . $functionId, [
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('image/svg+xml', $response['headers']['content-type']);
$this->assertStringContainsString('<svg', $response['body']);
$this->assertStringContainsString('disabled', $response['body']);
$this->assertStringContainsString('appwrite functions', $response['body']);
$this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
}
/**
* When badge is explicitly enabled on a site with no deployments, it shows 'no deployment'.
*/
public function testGetSiteBadgeNoDeployment(): void
{
$site = $this->client->call(Client::METHOD_POST, '/sites', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'siteId' => ID::unique(),
'name' => 'No Deployment Badge Site',
'framework' => 'other',
'adapter' => 'static',
'buildRuntime' => 'static-1',
'outputDirectory' => './',
'buildCommand' => '',
'installCommand' => '',
'fallbackFile' => '',
]);
$this->assertEquals(201, $site['headers']['status-code']);
$siteId = $site['body']['$id'];
$update = $this->client->call(Client::METHOD_PUT, '/sites/' . $siteId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'No Deployment Badge Site',
'framework' => 'other',
'adapter' => 'static',
'buildRuntime' => 'static-1',
'outputDirectory' => './',
'buildCommand' => '',
'installCommand' => '',
'fallbackFile' => '',
'deploymentBadge' => true,
]);
$this->assertEquals(200, $update['headers']['status-code']);
$this->assertTrue($update['body']['deploymentBadge']);
$response = $this->client->call(Client::METHOD_GET, '/badge/sites/' . $siteId, [
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('image/svg+xml', $response['headers']['content-type']);
$this->assertStringContainsString('<svg', $response['body']);
$this->assertStringContainsString('no deployment', $response['body']);
$this->assertStringContainsString('appwrite sites', $response['body']);
$this->assertStringContainsString('no-cache', $response['headers']['cache-control'] ?? '');
$this->client->call(Client::METHOD_DELETE, '/sites/' . $siteId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
}
/**
* When badge is explicitly enabled on a function with no deployments, it shows 'no deployment'.
*/
public function testGetFunctionBadgeNoDeployment(): void
{
$function = $this->client->call(Client::METHOD_POST, '/functions', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'functionId' => ID::unique(),
'name' => 'No Deployment Badge Function',
'runtime' => 'node-22',
'entrypoint' => 'index.js',
]);
$this->assertEquals(201, $function['headers']['status-code']);
$functionId = $function['body']['$id'];
$update = $this->client->call(Client::METHOD_PUT, '/functions/' . $functionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()), [
'name' => 'No Deployment Badge Function',
'runtime' => 'node-22',
'entrypoint' => 'index.js',
'deploymentBadge' => true,
]);
$this->assertEquals(200, $update['headers']['status-code']);
$this->assertTrue($update['body']['deploymentBadge']);
$response = $this->client->call(Client::METHOD_GET, '/badge/functions/' . $functionId, [
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('image/svg+xml', $response['headers']['content-type']);
$this->assertStringContainsString('<svg', $response['body']);
$this->assertStringContainsString('no deployment', $response['body']);
$this->assertStringContainsString('appwrite functions', $response['body']);
$this->assertStringContainsString('no-cache', $response['headers']['cache-control'] ?? '');
$this->client->call(Client::METHOD_DELETE, '/functions/' . $functionId, array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
], $this->getHeaders()));
}
public function testBadgeEndpointsArePublic(): void
{
$response = $this->client->call(Client::METHOD_GET, '/badge/sites/nonexistentid1234567', [
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('image/svg+xml', $response['headers']['content-type']);
$response = $this->client->call(Client::METHOD_GET, '/badge/functions/nonexistentid1234567', [
'x-appwrite-project' => $this->getProject()['$id'],
]);
$this->assertEquals(200, $response['headers']['status-code']);
$this->assertStringContainsString('image/svg+xml', $response['headers']['content-type']);
}
}