Merge branch '1.9.x' into feat/cache-circuit-breaker

This commit is contained in:
Chirag Aggarwal
2026-05-11 12:08:17 +05:30
committed by GitHub
6 changed files with 247 additions and 39 deletions
+20
View File
@@ -320,6 +320,26 @@ return [
'repoBranch' => 'main',
'changelog' => \realpath(__DIR__ . '/../../docs/sdks/claude-plugin/CHANGELOG.md'),
],
[
'key' => 'codex-plugin',
'name' => 'CodexPlugin',
'version' => '0.1.0',
'url' => 'https://github.com/appwrite/codex-plugin.git',
'enabled' => true,
'beta' => false,
'dev' => false,
'hidden' => false,
'spec' => 'static',
'family' => APP_SDK_PLATFORM_STATIC,
'prism' => 'codex-plugin',
'source' => \realpath(__DIR__ . '/../sdks/static-codex-plugin'),
'gitUrl' => 'git@github.com:appwrite/codex-plugin.git',
'gitRepoName' => 'codex-plugin',
'gitUserName' => 'appwrite',
'gitBranch' => 'dev',
'repoBranch' => 'main',
'changelog' => \realpath(__DIR__ . '/../../docs/sdks/codex-plugin/CHANGELOG.md'),
],
],
],
Generated
+14 -32
View File
@@ -4603,16 +4603,16 @@
},
{
"name": "utopia-php/migration",
"version": "1.10.1",
"version": "1.10.2",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/migration.git",
"reference": "759d6d61b327313cbeeeb4ea0c3e2459164b4827"
"reference": "211d01b90ccab9729029151c6c61f543bd755c2e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/759d6d61b327313cbeeeb4ea0c3e2459164b4827",
"reference": "759d6d61b327313cbeeeb4ea0c3e2459164b4827",
"url": "https://api.github.com/repos/utopia-php/migration/zipball/211d01b90ccab9729029151c6c61f543bd755c2e",
"reference": "211d01b90ccab9729029151c6c61f543bd755c2e",
"shasum": ""
},
"require": {
@@ -4638,25 +4638,7 @@
"Utopia\\Migration\\": "src/Migration"
}
},
"autoload-dev": {
"psr-4": {
"Utopia\\Tests\\": "tests/Migration"
}
},
"scripts": {
"test": [
"./vendor/bin/phpunit"
],
"lint": [
"./vendor/bin/pint --test"
],
"format": [
"./vendor/bin/pint"
],
"check": [
"./vendor/bin/phpstan analyse --level 3 src tests --memory-limit 2G"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@@ -4669,10 +4651,10 @@
"utopia"
],
"support": {
"source": "https://github.com/utopia-php/migration/tree/1.10.1",
"issues": "https://github.com/utopia-php/migration/issues"
"issues": "https://github.com/utopia-php/migration/issues",
"source": "https://github.com/utopia-php/migration/tree/1.10.2"
},
"time": "2026-05-07T07:23:57+00:00"
"time": "2026-05-08T06:25:47+00:00"
},
{
"name": "utopia-php/mongo",
@@ -5556,16 +5538,16 @@
"packages-dev": [
{
"name": "appwrite/sdk-generator",
"version": "1.27.5",
"version": "1.28.0",
"source": {
"type": "git",
"url": "https://github.com/appwrite/sdk-generator.git",
"reference": "9faa38b48d422f3da764a719712905c83b3922cb"
"reference": "e363fffd220172c5f1a5032038fa3fdafeeb2dfb"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/9faa38b48d422f3da764a719712905c83b3922cb",
"reference": "9faa38b48d422f3da764a719712905c83b3922cb",
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/e363fffd220172c5f1a5032038fa3fdafeeb2dfb",
"reference": "e363fffd220172c5f1a5032038fa3fdafeeb2dfb",
"shasum": ""
},
"require": {
@@ -5601,9 +5583,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.27.5"
"source": "https://github.com/appwrite/sdk-generator/tree/1.28.0"
},
"time": "2026-05-05T12:09:40+00:00"
"time": "2026-05-08T03:37:44+00:00"
},
{
"name": "brianium/paratest",
+35 -2
View File
@@ -72,7 +72,7 @@ class Google extends OAuth2
'https://oauth2.googleapis.com/token?' . \http_build_query([
'code' => $code,
'client_id' => $this->appID,
'client_secret' => $this->appSecret,
'client_secret' => $this->getClientSecret(),
'redirect_uri' => $this->callback,
'scope' => null,
'grant_type' => 'authorization_code'
@@ -95,7 +95,7 @@ class Google extends OAuth2
'https://oauth2.googleapis.com/token?' . \http_build_query([
'refresh_token' => $refreshToken,
'client_id' => $this->appID,
'client_secret' => $this->appSecret,
'client_secret' => $this->getClientSecret(),
'grant_type' => 'refresh_token'
])
), true);
@@ -177,4 +177,37 @@ class Google extends OAuth2
return $this->user;
}
/**
* Extracts the Client Secret from the JSON stored in appSecret
*
* @return string
*/
protected function getClientSecret(): string
{
$secret = $this->getAppSecret();
return $secret['clientSecret'] ?? $this->appSecret;
}
/**
* Decode the JSON stored in appSecret.
* Falls back to treating the raw string as the client secret for backwards compatibility.
*
* @return array
*/
protected function getAppSecret(): array
{
try {
$secret = \json_decode($this->appSecret, true, 512, JSON_THROW_ON_ERROR);
} catch (\Throwable $th) {
return ['clientSecret' => $this->appSecret];
}
if (!\is_array($secret)) {
return ['clientSecret' => $this->appSecret];
}
return $secret;
}
}
+4
View File
@@ -7,6 +7,7 @@ use Appwrite\SDK\Language\Android;
use Appwrite\SDK\Language\Apple;
use Appwrite\SDK\Language\ClaudePlugin;
use Appwrite\SDK\Language\CLI;
use Appwrite\SDK\Language\CodexPlugin;
use Appwrite\SDK\Language\CursorPlugin;
use Appwrite\SDK\Language\Dart;
use Appwrite\SDK\Language\Deno;
@@ -455,6 +456,9 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
case 'claude-plugin':
$config = new ClaudePlugin();
break;
case 'codex-plugin':
$config = new CodexPlugin();
break;
default:
throw new \Exception('Language "' . $language['key'] . '" not supported');
}
+20 -5
View File
@@ -50,6 +50,8 @@ class Comment
protected string $statePrefix = '[appwrite]: #';
protected ?string $tip = null;
/**
* @var mixed[] $builds
*/
@@ -81,7 +83,14 @@ class Comment
public function generateComment(): string
{
$json = \json_encode($this->builds);
if ($this->tip === null) {
$this->tip = $this->tips[\array_rand($this->tips)];
}
$json = \json_encode([
'builds' => $this->builds,
'tip' => $this->tip,
]);
$text = $this->statePrefix . \base64_encode($json) . "\n\n";
@@ -226,8 +235,7 @@ class Comment
$i++;
}
$tip = $this->tips[array_rand($this->tips)];
$text .= "\n<br>\n\n> [!TIP]\n> $tip\n\n";
$text .= "\n<br>\n\n> [!TIP]\n> {$this->tip}\n\n";
return $text;
}
@@ -252,8 +260,15 @@ class Comment
$json = \base64_decode($state);
$builds = \json_decode($json, true);
$this->builds = \is_array($builds) ? $builds : [];
$data = \json_decode($json, true);
if (\is_array($data) && \array_key_exists('builds', $data)) {
$this->builds = \is_array($data['builds']) ? $data['builds'] : [];
$this->tip = $data['tip'] ?? null;
} else {
// Backward compatibility with old state format (builds array only)
$this->builds = \is_array($data) ? $data : [];
}
return $this;
}
+154
View File
@@ -0,0 +1,154 @@
<?php
namespace Tests\Unit\Vcs;
use Appwrite\Vcs\Comment;
use PHPUnit\Framework\TestCase;
use Utopia\Database\Document;
class CommentTest extends TestCase
{
public function testTipIsPreservedAcrossMultipleGenerations(): void
{
$comment = new Comment(['consoleHostname' => 'localhost']);
$comment->addBuild(
new Document(['$id' => 'project1', 'name' => 'Test Project', 'region' => 'default']),
new Document(['$id' => 'func1', 'name' => 'Test Function']),
'function',
'ready',
'dep1',
['type' => 'logs'],
''
);
$first = $comment->generateComment();
$firstTip = $this->extractTip($first);
$this->assertNotNull($firstTip);
$this->assertNotEmpty($firstTip);
$second = $comment->generateComment();
$secondTip = $this->extractTip($second);
$this->assertEquals($firstTip, $secondTip);
}
public function testTipIsRestoredFromParsedComment(): void
{
$comment = new Comment(['consoleHostname' => 'localhost']);
$comment->addBuild(
new Document(['$id' => 'project1', 'name' => 'Test Project', 'region' => 'default']),
new Document(['$id' => 'func1', 'name' => 'Test Function']),
'function',
'ready',
'dep1',
['type' => 'logs'],
''
);
$original = $comment->generateComment();
$originalTip = $this->extractTip($original);
$parsed = new Comment(['consoleHostname' => 'localhost']);
$parsed->parseComment($original);
$parsed->addBuild(
new Document(['$id' => 'project1', 'name' => 'Test Project', 'region' => 'default']),
new Document(['$id' => 'func2', 'name' => 'Another Function']),
'function',
'building',
'dep2',
['type' => 'logs'],
''
);
$regenerated = $parsed->generateComment();
$regeneratedTip = $this->extractTip($regenerated);
$this->assertEquals($originalTip, $regeneratedTip);
}
public function testBackwardCompatibilityWithOldStateFormat(): void
{
$oldBuilds = [
'project1_func1' => [
'projectName' => 'Test Project',
'projectId' => 'project1',
'region' => 'default',
'resourceName' => 'Test Function',
'resourceId' => 'func1',
'resourceType' => 'function',
'buildStatus' => 'ready',
'deploymentId' => 'dep1',
'action' => ['type' => 'logs'],
'previewUrl' => '',
],
];
$oldState = '[appwrite]: #' . \base64_encode(\json_encode($oldBuilds)) . "\n\n";
$oldState .= "> [!TIP]\n> Old tip that should be ignored\n\n";
$comment = new Comment(['consoleHostname' => 'localhost']);
$comment->parseComment($oldState);
$new = $comment->generateComment();
$newTip = $this->extractTip($new);
$this->assertNotNull($newTip);
$this->assertNotEquals('Old tip that should be ignored', $newTip);
$this->assertContains($newTip, $this->getTips());
}
public function testParseOldStateFormatWithOnlyBuilds(): void
{
$oldBuilds = [
'project1_func1' => [
'projectName' => 'Test Project',
'projectId' => 'project1',
'region' => 'default',
'resourceName' => 'Test Function',
'resourceId' => 'func1',
'resourceType' => 'function',
'buildStatus' => 'ready',
'deploymentId' => 'dep1',
'action' => ['type' => 'logs'],
'previewUrl' => '',
],
];
$state = '[appwrite]: #' . \base64_encode(\json_encode($oldBuilds)) . "\n\n";
$comment = new Comment(['consoleHostname' => 'localhost']);
$comment->parseComment($state);
$this->assertEquals(false, $comment->isEmpty());
$first = $comment->generateComment();
$firstTip = $this->extractTip($first);
$this->assertNotNull($firstTip);
$this->assertNotEmpty($firstTip);
$this->assertContains($firstTip, $this->getTips());
$second = $comment->generateComment();
$secondTip = $this->extractTip($second);
$this->assertEquals($firstTip, $secondTip);
}
private function extractTip(string $comment): ?string
{
if (\preg_match('/> \[!TIP\]\n> (.+)/', $comment, $matches)) {
return $matches[1];
}
return null;
}
private function getTips(): array
{
$reflection = new \ReflectionClass(Comment::class);
$property = $reflection->getProperty('tips');
return $property->getValue(new Comment(['consoleHostname' => 'localhost']));
}
}